00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 #include <string.h>
00022 #include "libavutil/avstring.h"
00023 #include "libavutil/base64.h"
00024 #include "libavutil/dict.h"
00025 #include "libavutil/parseutils.h"
00026 #include "libavutil/opt.h"
00027 #include "libavcodec/xiph.h"
00028 #include "libavcodec/mpeg4audio.h"
00029 #include "avformat.h"
00030 #include "internal.h"
00031 #include "avc.h"
00032 #include "rtp.h"
00033 #if CONFIG_NETWORK
00034 #include "network.h"
00035 #endif
00036 
00037 #if CONFIG_RTP_MUXER
00038 #define MAX_EXTRADATA_SIZE ((INT_MAX - 10) / 2)
00039 
00040 struct sdp_session_level {
00041     int sdp_version;      
00042     int id;               
00043     int version;          
00044     int start_time;       
00046     int end_time;         
00048     int ttl;              
00049     const char *user;     
00050     const char *src_addr; 
00051     const char *src_type; 
00052     const char *dst_addr; 
00053     const char *dst_type; 
00054     const char *name;     
00055 };
00056 
00057 static void sdp_write_address(char *buff, int size, const char *dest_addr,
00058                               const char *dest_type, int ttl)
00059 {
00060     if (dest_addr) {
00061         if (!dest_type)
00062             dest_type = "IP4";
00063         if (ttl > 0 && !strcmp(dest_type, "IP4")) {
00064             
00065 
00066             av_strlcatf(buff, size, "c=IN %s %s/%d\r\n", dest_type, dest_addr, ttl);
00067         } else {
00068             av_strlcatf(buff, size, "c=IN %s %s\r\n", dest_type, dest_addr);
00069         }
00070     }
00071 }
00072 
00073 static void sdp_write_header(char *buff, int size, struct sdp_session_level *s)
00074 {
00075     av_strlcatf(buff, size, "v=%d\r\n"
00076                             "o=- %d %d IN %s %s\r\n"
00077                             "s=%s\r\n",
00078                             s->sdp_version,
00079                             s->id, s->version, s->src_type, s->src_addr,
00080                             s->name);
00081     sdp_write_address(buff, size, s->dst_addr, s->dst_type, s->ttl);
00082     av_strlcatf(buff, size, "t=%d %d\r\n"
00083                             "a=tool:libavformat " AV_STRINGIFY(LIBAVFORMAT_VERSION) "\r\n",
00084                             s->start_time, s->end_time);
00085 }
00086 
00087 #if CONFIG_NETWORK
00088 static int resolve_destination(char *dest_addr, int size, char *type,
00089                                int type_size)
00090 {
00091     struct addrinfo hints = { 0 }, *ai;
00092     int is_multicast;
00093 
00094     av_strlcpy(type, "IP4", type_size);
00095     if (!dest_addr[0])
00096         return 0;
00097 
00098     
00099 
00100 
00101     if (getaddrinfo(dest_addr, NULL, &hints, &ai))
00102         return 0;
00103     getnameinfo(ai->ai_addr, ai->ai_addrlen, dest_addr, size,
00104                 NULL, 0, NI_NUMERICHOST);
00105 #ifdef AF_INET6
00106     if (ai->ai_family == AF_INET6)
00107         av_strlcpy(type, "IP6", type_size);
00108 #endif
00109     is_multicast = ff_is_multicast_address(ai->ai_addr);
00110     freeaddrinfo(ai);
00111     return is_multicast;
00112 }
00113 #else
00114 static int resolve_destination(char *dest_addr, int size, char *type,
00115                                int type_size)
00116 {
00117     return 0;
00118 }
00119 #endif
00120 
00121 static int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url)
00122 {
00123     int port;
00124     const char *p;
00125     char proto[32];
00126 
00127     av_url_split(proto, sizeof(proto), NULL, 0, dest_addr, size, &port, NULL, 0, url);
00128 
00129     *ttl = 0;
00130 
00131     if (strcmp(proto, "rtp")) {
00132         
00133 
00134 
00135         return 0;
00136     }
00137 
00138     p = strchr(url, '?');
00139     if (p) {
00140         char buff[64];
00141 
00142         if (av_find_info_tag(buff, sizeof(buff), "ttl", p)) {
00143             *ttl = strtol(buff, NULL, 10);
00144         } else {
00145             *ttl = 5;
00146         }
00147     }
00148 
00149     return port;
00150 }
00151 
00152 #define MAX_PSET_SIZE 1024
00153 static char *extradata2psets(AVCodecContext *c)
00154 {
00155     char *psets, *p;
00156     const uint8_t *r;
00157     static const char pset_string[] = "; sprop-parameter-sets=";
00158     static const char profile_string[] = "; profile-level-id=";
00159     uint8_t *orig_extradata = NULL;
00160     int orig_extradata_size = 0;
00161     const uint8_t *sps = NULL, *sps_end;
00162 
00163     if (c->extradata_size > MAX_EXTRADATA_SIZE) {
00164         av_log(c, AV_LOG_ERROR, "Too much extradata!\n");
00165 
00166         return NULL;
00167     }
00168     if (c->extradata[0] == 1) {
00169         uint8_t *dummy_p;
00170         int dummy_int;
00171         AVBitStreamFilterContext *bsfc= av_bitstream_filter_init("h264_mp4toannexb");
00172 
00173         if (!bsfc) {
00174             av_log(c, AV_LOG_ERROR, "Cannot open the h264_mp4toannexb BSF!\n");
00175 
00176             return NULL;
00177         }
00178 
00179         orig_extradata_size = c->extradata_size;
00180         orig_extradata = av_mallocz(orig_extradata_size +
00181                                     FF_INPUT_BUFFER_PADDING_SIZE);
00182         if (!orig_extradata) {
00183             av_bitstream_filter_close(bsfc);
00184             return NULL;
00185         }
00186         memcpy(orig_extradata, c->extradata, orig_extradata_size);
00187         av_bitstream_filter_filter(bsfc, c, NULL, &dummy_p, &dummy_int, NULL, 0, 0);
00188         av_bitstream_filter_close(bsfc);
00189     }
00190 
00191     psets = av_mallocz(MAX_PSET_SIZE);
00192     if (psets == NULL) {
00193         av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the parameter sets.\n");
00194         av_free(orig_extradata);
00195         return NULL;
00196     }
00197     memcpy(psets, pset_string, strlen(pset_string));
00198     p = psets + strlen(pset_string);
00199     r = ff_avc_find_startcode(c->extradata, c->extradata + c->extradata_size);
00200     while (r < c->extradata + c->extradata_size) {
00201         const uint8_t *r1;
00202         uint8_t nal_type;
00203 
00204         while (!*(r++));
00205         nal_type = *r & 0x1f;
00206         r1 = ff_avc_find_startcode(r, c->extradata + c->extradata_size);
00207         if (nal_type != 7 && nal_type != 8) { 
00208             r = r1;
00209             continue;
00210         }
00211         if (p != (psets + strlen(pset_string))) {
00212             *p = ',';
00213             p++;
00214         }
00215         if (!sps) {
00216             sps = r;
00217             sps_end = r1;
00218         }
00219         if (av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r) == NULL) {
00220             av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %td %td!\n", MAX_PSET_SIZE - (p - psets), r1 - r);
00221             av_free(psets);
00222 
00223             return NULL;
00224         }
00225         p += strlen(p);
00226         r = r1;
00227     }
00228     if (sps && sps_end - sps >= 4) {
00229         memcpy(p, profile_string, strlen(profile_string));
00230         p += strlen(p);
00231         ff_data_to_hex(p, sps + 1, 3, 0);
00232         p[6] = '\0';
00233     }
00234     if (orig_extradata) {
00235         av_free(c->extradata);
00236         c->extradata      = orig_extradata;
00237         c->extradata_size = orig_extradata_size;
00238     }
00239 
00240     return psets;
00241 }
00242 
00243 static char *extradata2config(AVCodecContext *c)
00244 {
00245     char *config;
00246 
00247     if (c->extradata_size > MAX_EXTRADATA_SIZE) {
00248         av_log(c, AV_LOG_ERROR, "Too much extradata!\n");
00249 
00250         return NULL;
00251     }
00252     config = av_malloc(10 + c->extradata_size * 2);
00253     if (config == NULL) {
00254         av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");
00255         return NULL;
00256     }
00257     memcpy(config, "; config=", 9);
00258     ff_data_to_hex(config + 9, c->extradata, c->extradata_size, 0);
00259     config[9 + c->extradata_size * 2] = 0;
00260 
00261     return config;
00262 }
00263 
00264 static char *xiph_extradata2config(AVCodecContext *c)
00265 {
00266     char *config, *encoded_config;
00267     uint8_t *header_start[3];
00268     int headers_len, header_len[3], config_len;
00269     int first_header_size;
00270 
00271     switch (c->codec_id) {
00272     case AV_CODEC_ID_THEORA:
00273         first_header_size = 42;
00274         break;
00275     case AV_CODEC_ID_VORBIS:
00276         first_header_size = 30;
00277         break;
00278     default:
00279         av_log(c, AV_LOG_ERROR, "Unsupported Xiph codec ID\n");
00280         return NULL;
00281     }
00282 
00283     if (avpriv_split_xiph_headers(c->extradata, c->extradata_size,
00284                               first_header_size, header_start,
00285                               header_len) < 0) {
00286         av_log(c, AV_LOG_ERROR, "Extradata corrupt.\n");
00287         return NULL;
00288     }
00289 
00290     headers_len = header_len[0] + header_len[2];
00291     config_len = 4 +          
00292                  3 +          
00293                  2 +          
00294                  1 +          
00295                  2 +          
00296                  headers_len; 
00297 
00298     config = av_malloc(config_len);
00299     if (!config)
00300         goto xiph_fail;
00301 
00302     encoded_config = av_malloc(AV_BASE64_SIZE(config_len));
00303     if (!encoded_config) {
00304         av_free(config);
00305         goto xiph_fail;
00306     }
00307 
00308     config[0] = config[1] = config[2] = 0;
00309     config[3] = 1;
00310     config[4] = (RTP_XIPH_IDENT >> 16) & 0xff;
00311     config[5] = (RTP_XIPH_IDENT >>  8) & 0xff;
00312     config[6] = (RTP_XIPH_IDENT      ) & 0xff;
00313     config[7] = (headers_len >> 8) & 0xff;
00314     config[8] = headers_len & 0xff;
00315     config[9] = 2;
00316     config[10] = header_len[0];
00317     config[11] = 0; 
00318     memcpy(config + 12, header_start[0], header_len[0]);
00319     memcpy(config + 12 + header_len[0], header_start[2], header_len[2]);
00320 
00321     av_base64_encode(encoded_config, AV_BASE64_SIZE(config_len),
00322                      config, config_len);
00323     av_free(config);
00324 
00325     return encoded_config;
00326 
00327 xiph_fail:
00328     av_log(c, AV_LOG_ERROR,
00329            "Not enough memory for configuration string\n");
00330     return NULL;
00331 }
00332 
00333 static int latm_context2profilelevel(AVCodecContext *c)
00334 {
00335     
00336 
00337 
00338 
00339     int profile_level = 0x2B;
00340 
00341     
00342 
00343 
00344     if (c->sample_rate <= 24000) {
00345         if (c->channels <= 2)
00346             profile_level = 0x28; 
00347     } else if (c->sample_rate <= 48000) {
00348         if (c->channels <= 2) {
00349             profile_level = 0x29; 
00350         } else if (c->channels <= 5) {
00351             profile_level = 0x2A; 
00352         }
00353     } else if (c->sample_rate <= 96000) {
00354         if (c->channels <= 5) {
00355             profile_level = 0x2B; 
00356         }
00357     }
00358 
00359     return profile_level;
00360 }
00361 
00362 static char *latm_context2config(AVCodecContext *c)
00363 {
00364     
00365 
00366 
00367 
00368     uint8_t config_byte[6];
00369     int rate_index;
00370     char *config;
00371 
00372     for (rate_index = 0; rate_index < 16; rate_index++)
00373         if (avpriv_mpeg4audio_sample_rates[rate_index] == c->sample_rate)
00374             break;
00375     if (rate_index == 16) {
00376         av_log(c, AV_LOG_ERROR, "Unsupported sample rate\n");
00377         return NULL;
00378     }
00379 
00380     config_byte[0] = 0x40;
00381     config_byte[1] = 0;
00382     config_byte[2] = 0x20 | rate_index;
00383     config_byte[3] = c->channels << 4;
00384     config_byte[4] = 0x3f;
00385     config_byte[5] = 0xc0;
00386 
00387     config = av_malloc(6*2+1);
00388     if (!config) {
00389         av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n");
00390         return NULL;
00391     }
00392     ff_data_to_hex(config, config_byte, 6, 1);
00393     config[12] = 0;
00394 
00395     return config;
00396 }
00397 
00398 static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type, AVFormatContext *fmt)
00399 {
00400     char *config = NULL;
00401 
00402     switch (c->codec_id) {
00403         case AV_CODEC_ID_H264: {
00404             int mode = 1;
00405             if (fmt && fmt->oformat->priv_class &&
00406                 av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0"))
00407                 mode = 0;
00408             if (c->extradata_size) {
00409                 config = extradata2psets(c);
00410             }
00411             av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n"
00412                                     "a=fmtp:%d packetization-mode=%d%s\r\n",
00413                                      payload_type,
00414                                      payload_type, mode, config ? config : "");
00415             break;
00416         }
00417         case AV_CODEC_ID_H263:
00418         case AV_CODEC_ID_H263P:
00419             
00420 
00421 
00422 
00423             if (!fmt || !fmt->oformat->priv_class ||
00424                 !av_opt_flag_is_set(fmt->priv_data, "rtpflags", "rfc2190") ||
00425                 c->codec_id == AV_CODEC_ID_H263P)
00426             av_strlcatf(buff, size, "a=rtpmap:%d H263-2000/90000\r\n"
00427                                     "a=framesize:%d %d-%d\r\n",
00428                                     payload_type,
00429                                     payload_type, c->width, c->height);
00430             break;
00431         case AV_CODEC_ID_MPEG4:
00432             if (c->extradata_size) {
00433                 config = extradata2config(c);
00434             }
00435             av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n"
00436                                     "a=fmtp:%d profile-level-id=1%s\r\n",
00437                                      payload_type,
00438                                      payload_type, config ? config : "");
00439             break;
00440         case AV_CODEC_ID_AAC:
00441             if (fmt && fmt->oformat && fmt->oformat->priv_class &&
00442                 av_opt_flag_is_set(fmt->priv_data, "rtpflags", "latm")) {
00443                 config = latm_context2config(c);
00444                 if (!config)
00445                     return NULL;
00446                 av_strlcatf(buff, size, "a=rtpmap:%d MP4A-LATM/%d/%d\r\n"
00447                                         "a=fmtp:%d profile-level-id=%d;cpresent=0;config=%s\r\n",
00448                                          payload_type, c->sample_rate, c->channels,
00449                                          payload_type, latm_context2profilelevel(c), config);
00450             } else {
00451                 if (c->extradata_size) {
00452                     config = extradata2config(c);
00453                 } else {
00454                     
00455 
00456 
00457                     av_log(c, AV_LOG_ERROR, "AAC with no global headers is currently not supported.\n");
00458                     return NULL;
00459                 }
00460                 if (config == NULL) {
00461                     return NULL;
00462                 }
00463                 av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n"
00464                                         "a=fmtp:%d profile-level-id=1;"
00465                                         "mode=AAC-hbr;sizelength=13;indexlength=3;"
00466                                         "indexdeltalength=3%s\r\n",
00467                                          payload_type, c->sample_rate, c->channels,
00468                                          payload_type, config);
00469             }
00470             break;
00471         case AV_CODEC_ID_PCM_S16BE:
00472             if (payload_type >= RTP_PT_PRIVATE)
00473                 av_strlcatf(buff, size, "a=rtpmap:%d L16/%d/%d\r\n",
00474                                          payload_type,
00475                                          c->sample_rate, c->channels);
00476             break;
00477         case AV_CODEC_ID_PCM_MULAW:
00478             if (payload_type >= RTP_PT_PRIVATE)
00479                 av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n",
00480                                          payload_type,
00481                                          c->sample_rate, c->channels);
00482             break;
00483         case AV_CODEC_ID_PCM_ALAW:
00484             if (payload_type >= RTP_PT_PRIVATE)
00485                 av_strlcatf(buff, size, "a=rtpmap:%d PCMA/%d/%d\r\n",
00486                                          payload_type,
00487                                          c->sample_rate, c->channels);
00488             break;
00489         case AV_CODEC_ID_AMR_NB:
00490             av_strlcatf(buff, size, "a=rtpmap:%d AMR/%d/%d\r\n"
00491                                     "a=fmtp:%d octet-align=1\r\n",
00492                                      payload_type, c->sample_rate, c->channels,
00493                                      payload_type);
00494             break;
00495         case AV_CODEC_ID_AMR_WB:
00496             av_strlcatf(buff, size, "a=rtpmap:%d AMR-WB/%d/%d\r\n"
00497                                     "a=fmtp:%d octet-align=1\r\n",
00498                                      payload_type, c->sample_rate, c->channels,
00499                                      payload_type);
00500             break;
00501         case AV_CODEC_ID_VORBIS:
00502             if (c->extradata_size)
00503                 config = xiph_extradata2config(c);
00504             else
00505                 av_log(c, AV_LOG_ERROR, "Vorbis configuration info missing\n");
00506             if (!config)
00507                 return NULL;
00508 
00509             av_strlcatf(buff, size, "a=rtpmap:%d vorbis/%d/%d\r\n"
00510                                     "a=fmtp:%d configuration=%s\r\n",
00511                                     payload_type, c->sample_rate, c->channels,
00512                                     payload_type, config);
00513             break;
00514         case AV_CODEC_ID_THEORA: {
00515             const char *pix_fmt;
00516             if (c->extradata_size)
00517                 config = xiph_extradata2config(c);
00518             else
00519                 av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n");
00520             if (!config)
00521                 return NULL;
00522 
00523             switch (c->pix_fmt) {
00524             case PIX_FMT_YUV420P:
00525                 pix_fmt = "YCbCr-4:2:0";
00526                 break;
00527             case PIX_FMT_YUV422P:
00528                 pix_fmt = "YCbCr-4:2:2";
00529                 break;
00530             case PIX_FMT_YUV444P:
00531                 pix_fmt = "YCbCr-4:4:4";
00532                 break;
00533             default:
00534                 av_log(c, AV_LOG_ERROR, "Unsupported pixel format.\n");
00535                 return NULL;
00536             }
00537 
00538             av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n"
00539                                     "a=fmtp:%d delivery-method=inline; "
00540                                     "width=%d; height=%d; sampling=%s; "
00541                                     "configuration=%s\r\n",
00542                                     payload_type, payload_type,
00543                                     c->width, c->height, pix_fmt, config);
00544             break;
00545         }
00546         case AV_CODEC_ID_VP8:
00547             av_strlcatf(buff, size, "a=rtpmap:%d VP8/90000\r\n",
00548                                      payload_type);
00549             break;
00550         case AV_CODEC_ID_MJPEG:
00551             if (payload_type >= RTP_PT_PRIVATE)
00552                 av_strlcatf(buff, size, "a=rtpmap:%d JPEG/90000\r\n",
00553                                          payload_type);
00554             break;
00555         case AV_CODEC_ID_ADPCM_G722:
00556             if (payload_type >= RTP_PT_PRIVATE)
00557                 av_strlcatf(buff, size, "a=rtpmap:%d G722/%d/%d\r\n",
00558                                          payload_type,
00559                                          8000, c->channels);
00560             break;
00561         case AV_CODEC_ID_ADPCM_G726: {
00562             if (payload_type >= RTP_PT_PRIVATE)
00563                 av_strlcatf(buff, size, "a=rtpmap:%d G726-%d/%d\r\n",
00564                                          payload_type,
00565                                          c->bits_per_coded_sample*8,
00566                                          c->sample_rate);
00567             break;
00568         }
00569         case AV_CODEC_ID_ILBC:
00570             av_strlcatf(buff, size, "a=rtpmap:%d iLBC/%d\r\n"
00571                                     "a=fmtp:%d mode=%d\r\n",
00572                                      payload_type, c->sample_rate,
00573                                      payload_type, c->block_align == 38 ? 20 : 30);
00574             break;
00575         case AV_CODEC_ID_SPEEX:
00576             av_strlcatf(buff, size, "a=rtpmap:%d speex/%d\r\n",
00577                                      payload_type, c->sample_rate);
00578             break;
00579         default:
00580             
00581             break;
00582     }
00583 
00584     av_free(config);
00585 
00586     return buff;
00587 }
00588 
00589 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, const char *dest_type, int port, int ttl, AVFormatContext *fmt)
00590 {
00591     const char *type;
00592     int payload_type;
00593 
00594     payload_type = ff_rtp_get_payload_type(fmt, c);
00595 
00596     switch (c->codec_type) {
00597         case AVMEDIA_TYPE_VIDEO   : type = "video"      ; break;
00598         case AVMEDIA_TYPE_AUDIO   : type = "audio"      ; break;
00599         case AVMEDIA_TYPE_SUBTITLE: type = "text"       ; break;
00600         default                 : type = "application"; break;
00601     }
00602 
00603     av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type);
00604     sdp_write_address(buff, size, dest_addr, dest_type, ttl);
00605     if (c->bit_rate) {
00606         av_strlcatf(buff, size, "b=AS:%d\r\n", c->bit_rate / 1000);
00607     }
00608 
00609     sdp_write_media_attributes(buff, size, c, payload_type, fmt);
00610 }
00611 
00612 int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
00613 {
00614     AVDictionaryEntry *title = av_dict_get(ac[0]->metadata, "title", NULL, 0);
00615     struct sdp_session_level s = { 0 };
00616     int i, j, port, ttl, is_multicast;
00617     char dst[32], dst_type[5];
00618 
00619     memset(buf, 0, size);
00620     s.user = "-";
00621     s.src_addr = "127.0.0.1";    
00622     s.src_type = "IP4";
00623     s.name = title ? title->value : "No Name";
00624 
00625     port = 0;
00626     ttl = 0;
00627     if (n_files == 1) {
00628         port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->filename);
00629         is_multicast = resolve_destination(dst, sizeof(dst), dst_type,
00630                                            sizeof(dst_type));
00631         if (!is_multicast)
00632             ttl = 0;
00633         if (dst[0]) {
00634             s.dst_addr = dst;
00635             s.dst_type = dst_type;
00636             s.ttl = ttl;
00637             if (!strcmp(dst_type, "IP6")) {
00638                 s.src_addr = "::1";
00639                 s.src_type = "IP6";
00640             }
00641         }
00642     }
00643     sdp_write_header(buf, size, &s);
00644 
00645     dst[0] = 0;
00646     for (i = 0; i < n_files; i++) {
00647         if (n_files != 1) {
00648             port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename);
00649             is_multicast = resolve_destination(dst, sizeof(dst), dst_type,
00650                                                sizeof(dst_type));
00651             if (!is_multicast)
00652                 ttl = 0;
00653         }
00654         for (j = 0; j < ac[i]->nb_streams; j++) {
00655             ff_sdp_write_media(buf, size,
00656                                   ac[i]->streams[j]->codec, dst[0] ? dst : NULL,
00657                                   dst_type, (port > 0) ? port + j * 2 : 0, ttl,
00658                                   ac[i]);
00659             if (port <= 0) {
00660                 av_strlcatf(buf, size,
00661                                    "a=control:streamid=%d\r\n", i + j);
00662             }
00663         }
00664     }
00665 
00666     return 0;
00667 }
00668 #else
00669 int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size)
00670 {
00671     return AVERROR(ENOSYS);
00672 }
00673 
00674 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, const char *dest_type, int port, int ttl, AVFormatContext *fmt)
00675 {
00676 }
00677 #endif