00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avstring.h"
00022 #include "avformat.h"
00023 #include "rtp.h"
00024
00025 #ifdef CONFIG_RTP_MUXER
00026 #define MAX_EXTRADATA_SIZE ((INT_MAX - 10) / 2)
00027
00028 struct sdp_session_level {
00029 int sdp_version;
00030 int id;
00031 int version;
00032 int start_time;
00034 int end_time;
00036 int ttl;
00037 const char *user;
00038 const char *src_addr;
00039 const char *dst_addr;
00040 const char *name;
00041 };
00042
00043 static void dest_write(char *buff, int size, const char *dest_addr, int ttl)
00044 {
00045 if (dest_addr) {
00046 if (ttl > 0) {
00047 av_strlcatf(buff, size, "c=IN IP4 %s/%d\r\n", dest_addr, ttl);
00048 } else {
00049 av_strlcatf(buff, size, "c=IN IP4 %s\r\n", dest_addr);
00050 }
00051 }
00052 }
00053
00054 static void sdp_write_header(char *buff, int size, struct sdp_session_level *s)
00055 {
00056 av_strlcatf(buff, size, "v=%d\r\n"
00057 "o=- %d %d IN IPV4 %s\r\n"
00058 "t=%d %d\r\n"
00059 "s=%s\r\n"
00060 "a=tool:libavformat\r\n",
00061 s->sdp_version,
00062 s->id, s->version, s->src_addr,
00063 s->start_time, s->end_time,
00064 s->name[0] ? s->name : "No Name");
00065 dest_write(buff, size, s->dst_addr, s->ttl);
00066 }
00067
00068 static int get_address(char *dest_addr, int size, int *ttl, const char *url)
00069 {
00070 int port;
00071 const char *p;
00072
00073 url_split(NULL, 0, NULL, 0, dest_addr, size, &port, NULL, 0, url);
00074
00075 *ttl = 0;
00076 p = strchr(url, '?');
00077 if (p) {
00078 char buff[64];
00079 int is_multicast = find_info_tag(buff, sizeof(buff), "multicast", p);
00080
00081 if (is_multicast) {
00082 if (find_info_tag(buff, sizeof(buff), "ttl", p)) {
00083 *ttl = strtol(buff, NULL, 10);
00084 } else {
00085 *ttl = 5;
00086 }
00087 }
00088 }
00089
00090 return port;
00091 }
00092
00093 static void digit_to_char(char *dst, uint8_t src)
00094 {
00095 if (src < 10) {
00096 *dst = '0' + src;
00097 } else {
00098 *dst = 'A' + src - 10;
00099 }
00100 }
00101
00102 static char *data_to_hex(char *buff, const uint8_t *src, int s)
00103 {
00104 int i;
00105
00106 for(i = 0; i < s; i++) {
00107 digit_to_char(buff + 2 * i, src[i] >> 4);
00108 digit_to_char(buff + 2 * i + 1, src[i] & 0xF);
00109 }
00110
00111 return buff;
00112 }
00113
00114 static char *extradata2config(const uint8_t *extradata, int extradata_size)
00115 {
00116 char *config;
00117
00118 if (extradata_size > MAX_EXTRADATA_SIZE) {
00119 av_log(NULL, AV_LOG_ERROR, "Too many extra data!\n");
00120
00121 return NULL;
00122 }
00123 config = av_malloc(10 + extradata_size * 2);
00124 if (config == NULL) {
00125 av_log(NULL, AV_LOG_ERROR, "Cannot allocate memory for the config info\n");
00126 return NULL;
00127 }
00128 memcpy(config, "; config=", 9);
00129 data_to_hex(config + 9, extradata, extradata_size);
00130 config[9 + extradata_size * 2] = 0;
00131
00132 return config;
00133 }
00134
00135 static char *sdp_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type)
00136 {
00137 char *config = NULL;
00138
00139 switch (c->codec_id) {
00140 case CODEC_ID_MPEG4:
00141 if (c->extradata_size) {
00142 config = extradata2config(c->extradata, c->extradata_size);
00143 }
00144 av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n"
00145 "a=fmtp:%d profile-level-id=1%s\r\n",
00146 payload_type,
00147 payload_type, config ? config : "");
00148 break;
00149 case CODEC_ID_AAC:
00150 if (c->extradata_size) {
00151 config = extradata2config(c->extradata, c->extradata_size);
00152 } else {
00153
00154
00155
00156 av_log(NULL, AV_LOG_ERROR, "AAC with no global headers is currently not supported\n");
00157 return NULL;
00158 }
00159 if (config == NULL) {
00160 return NULL;
00161 }
00162 av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"
00163 "a=fmtp:%d profile-level-id=1;"
00164 "mode=AAC-hbr;sizelength=13;indexlength=3;"
00165 "indexdeltalength=3%s\r\n",
00166 payload_type, c->sample_rate, c->channels,
00167 payload_type, config);
00168 break;
00169 case CODEC_ID_PCM_S16BE:
00170 if (payload_type >= 96)
00171 av_strlcatf(buff, size, "a=rtpmap:%d L16/%d/%d\r\n",
00172 payload_type,
00173 c->sample_rate, c->channels);
00174 break;
00175 case CODEC_ID_PCM_MULAW:
00176 if (payload_type >= 96)
00177 av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n",
00178 payload_type,
00179 c->sample_rate, c->channels);
00180 break;
00181 case CODEC_ID_PCM_ALAW:
00182 if (payload_type >= 96)
00183 av_strlcatf(buff, size, "a=rtpmap:%d PCMA/%d/%d\r\n",
00184 payload_type,
00185 c->sample_rate, c->channels);
00186 break;
00187 default:
00188
00189 break;
00190 }
00191
00192 av_free(config);
00193
00194 return buff;
00195 }
00196
00197 static void sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, int port, int ttl)
00198 {
00199 const char *type;
00200 int payload_type;
00201
00202 payload_type = rtp_get_payload_type(c);
00203 if (payload_type < 0) {
00204 payload_type = 96;
00205 }
00206
00207 switch (c->codec_type) {
00208 case CODEC_TYPE_VIDEO : type = "video" ; break;
00209 case CODEC_TYPE_AUDIO : type = "audio" ; break;
00210 case CODEC_TYPE_SUBTITLE: type = "text" ; break;
00211 default : type = "application"; break;
00212 }
00213
00214 av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type);
00215 dest_write(buff, size, dest_addr, ttl);
00216
00217 sdp_media_attributes(buff, size, c, payload_type);
00218 }
00219
00220 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size)
00221 {
00222 struct sdp_session_level s;
00223 int i, j, port, ttl;
00224 char dst[32];
00225
00226 memset(buff, 0, size);
00227 memset(&s, 0, sizeof(struct sdp_session_level));
00228 s.user = "-";
00229 s.src_addr = "127.0.0.1";
00230 s.name = ac[0]->title;
00231
00232 port = 0;
00233 ttl = 0;
00234 if (n_files == 1) {
00235 port = get_address(dst, sizeof(dst), &ttl, ac[0]->filename);
00236 if (port > 0) {
00237 s.dst_addr = dst;
00238 s.ttl = ttl;
00239 }
00240 }
00241 sdp_write_header(buff, size, &s);
00242
00243 dst[0] = 0;
00244 for (i = 0; i < n_files; i++) {
00245 if (n_files != 1) {
00246 port = get_address(dst, sizeof(dst), &ttl, ac[i]->filename);
00247 }
00248 for (j = 0; j < ac[i]->nb_streams; j++) {
00249 sdp_write_media(buff, size,
00250 ac[i]->streams[j]->codec, dst[0] ? dst : NULL,
00251 (port > 0) ? port + j * 2 : 0, ttl);
00252 if (port <= 0) {
00253 av_strlcatf(buff, size,
00254 "a=control:streamid=%d\r\n", i + j);
00255 }
00256 }
00257 }
00258
00259 return 0;
00260 }
00261 #else
00262 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size)
00263 {
00264 return AVERROR(ENOSYS);
00265 }
00266 #endif