Libav
|
00001 /* 00002 * copyright (c) 2007 Luca Abeni 00003 * 00004 * This file is part of FFmpeg. 00005 * 00006 * FFmpeg is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * FFmpeg is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with FFmpeg; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <string.h> 00022 #include "libavutil/avstring.h" 00023 #include "libavutil/base64.h" 00024 #include "avformat.h" 00025 #include "internal.h" 00026 #include "avc.h" 00027 #include "rtp.h" 00028 #if CONFIG_NETWORK 00029 #include "network.h" 00030 #endif 00031 00032 #if CONFIG_RTP_MUXER 00033 #define MAX_EXTRADATA_SIZE ((INT_MAX - 10) / 2) 00034 00035 struct sdp_session_level { 00036 int sdp_version; 00037 int id; 00038 int version; 00039 int start_time; 00041 int end_time; 00043 int ttl; 00044 const char *user; 00045 const char *src_addr; 00046 const char *dst_addr; 00047 const char *name; 00048 }; 00049 00050 static void sdp_write_address(char *buff, int size, const char *dest_addr, int ttl) 00051 { 00052 if (dest_addr) { 00053 if (ttl > 0) { 00054 av_strlcatf(buff, size, "c=IN IP4 %s/%d\r\n", dest_addr, ttl); 00055 } else { 00056 av_strlcatf(buff, size, "c=IN IP4 %s\r\n", dest_addr); 00057 } 00058 } 00059 } 00060 00061 static void sdp_write_header(char *buff, int size, struct sdp_session_level *s) 00062 { 00063 av_strlcatf(buff, size, "v=%d\r\n" 00064 "o=- %d %d IN IP4 %s\r\n" 00065 "s=%s\r\n", 00066 s->sdp_version, 00067 s->id, s->version, s->src_addr, 00068 s->name); 00069 sdp_write_address(buff, size, s->dst_addr, s->ttl); 00070 av_strlcatf(buff, size, "t=%d %d\r\n" 00071 "a=tool:libavformat " AV_STRINGIFY(LIBAVFORMAT_VERSION) "\r\n", 00072 s->start_time, s->end_time); 00073 } 00074 00075 #if CONFIG_NETWORK 00076 static void resolve_destination(char *dest_addr, int size) 00077 { 00078 struct addrinfo hints, *ai, *cur; 00079 00080 if (!dest_addr[0]) 00081 return; 00082 00083 /* Resolve the destination, since it must be written 00084 * as a numeric IP address in the SDP. */ 00085 00086 memset(&hints, 0, sizeof(hints)); 00087 /* We only support IPv4 addresses in the SDP at the moment. */ 00088 hints.ai_family = AF_INET; 00089 if (getaddrinfo(dest_addr, NULL, &hints, &ai)) 00090 return; 00091 for (cur = ai; cur; cur = cur->ai_next) { 00092 if (cur->ai_family == AF_INET) { 00093 getnameinfo(cur->ai_addr, cur->ai_addrlen, dest_addr, size, 00094 NULL, 0, NI_NUMERICHOST); 00095 break; 00096 } 00097 } 00098 freeaddrinfo(ai); 00099 } 00100 #else 00101 static void resolve_destination(char *dest_addr, int size) 00102 { 00103 } 00104 #endif 00105 00106 static int sdp_get_address(char *dest_addr, int size, int *ttl, const char *url) 00107 { 00108 int port; 00109 const char *p; 00110 char proto[32]; 00111 00112 ff_url_split(proto, sizeof(proto), NULL, 0, dest_addr, size, &port, NULL, 0, url); 00113 00114 *ttl = 0; 00115 00116 if (strcmp(proto, "rtp")) { 00117 /* The url isn't for the actual rtp sessions, 00118 * don't parse out anything else than the destination. 00119 */ 00120 return 0; 00121 } 00122 00123 p = strchr(url, '?'); 00124 if (p) { 00125 char buff[64]; 00126 int is_multicast = find_info_tag(buff, sizeof(buff), "multicast", p); 00127 00128 if (is_multicast) { 00129 if (find_info_tag(buff, sizeof(buff), "ttl", p)) { 00130 *ttl = strtol(buff, NULL, 10); 00131 } else { 00132 *ttl = 5; 00133 } 00134 } 00135 } 00136 00137 return port; 00138 } 00139 00140 #define MAX_PSET_SIZE 1024 00141 static char *extradata2psets(AVCodecContext *c) 00142 { 00143 char *psets, *p; 00144 const uint8_t *r; 00145 const char *pset_string = "; sprop-parameter-sets="; 00146 00147 if (c->extradata_size > MAX_EXTRADATA_SIZE) { 00148 av_log(c, AV_LOG_ERROR, "Too much extradata!\n"); 00149 00150 return NULL; 00151 } 00152 00153 psets = av_mallocz(MAX_PSET_SIZE); 00154 if (psets == NULL) { 00155 av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the parameter sets.\n"); 00156 return NULL; 00157 } 00158 memcpy(psets, pset_string, strlen(pset_string)); 00159 p = psets + strlen(pset_string); 00160 r = ff_avc_find_startcode(c->extradata, c->extradata + c->extradata_size); 00161 while (r < c->extradata + c->extradata_size) { 00162 const uint8_t *r1; 00163 uint8_t nal_type; 00164 00165 while (!*(r++)); 00166 nal_type = *r & 0x1f; 00167 r1 = ff_avc_find_startcode(r, c->extradata + c->extradata_size); 00168 if (nal_type != 7 && nal_type != 8) { /* Only output SPS and PPS */ 00169 r = r1; 00170 continue; 00171 } 00172 if (p != (psets + strlen(pset_string))) { 00173 *p = ','; 00174 p++; 00175 } 00176 if (av_base64_encode(p, MAX_PSET_SIZE - (p - psets), r, r1 - r) == NULL) { 00177 av_log(c, AV_LOG_ERROR, "Cannot Base64-encode %td %td!\n", MAX_PSET_SIZE - (p - psets), r1 - r); 00178 av_free(psets); 00179 00180 return NULL; 00181 } 00182 p += strlen(p); 00183 r = r1; 00184 } 00185 00186 return psets; 00187 } 00188 00189 static char *extradata2config(AVCodecContext *c) 00190 { 00191 char *config; 00192 00193 if (c->extradata_size > MAX_EXTRADATA_SIZE) { 00194 av_log(c, AV_LOG_ERROR, "Too much extradata!\n"); 00195 00196 return NULL; 00197 } 00198 config = av_malloc(10 + c->extradata_size * 2); 00199 if (config == NULL) { 00200 av_log(c, AV_LOG_ERROR, "Cannot allocate memory for the config info.\n"); 00201 return NULL; 00202 } 00203 memcpy(config, "; config=", 9); 00204 ff_data_to_hex(config + 9, c->extradata, c->extradata_size, 0); 00205 config[9 + c->extradata_size * 2] = 0; 00206 00207 return config; 00208 } 00209 00210 static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type) 00211 { 00212 char *config = NULL; 00213 00214 switch (c->codec_id) { 00215 case CODEC_ID_H264: 00216 if (c->extradata_size) { 00217 config = extradata2psets(c); 00218 } 00219 av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n" 00220 "a=fmtp:%d packetization-mode=1%s\r\n", 00221 payload_type, 00222 payload_type, config ? config : ""); 00223 break; 00224 case CODEC_ID_H263: 00225 case CODEC_ID_H263P: 00226 av_strlcatf(buff, size, "a=rtpmap:%d H263-2000/90000\r\n", payload_type); 00227 break; 00228 case CODEC_ID_MPEG4: 00229 if (c->extradata_size) { 00230 config = extradata2config(c); 00231 } 00232 av_strlcatf(buff, size, "a=rtpmap:%d MP4V-ES/90000\r\n" 00233 "a=fmtp:%d profile-level-id=1%s\r\n", 00234 payload_type, 00235 payload_type, config ? config : ""); 00236 break; 00237 case CODEC_ID_AAC: 00238 if (c->extradata_size) { 00239 config = extradata2config(c); 00240 } else { 00241 /* FIXME: maybe we can forge config information based on the 00242 * codec parameters... 00243 */ 00244 av_log(c, AV_LOG_ERROR, "AAC with no global headers is currently not supported.\n"); 00245 return NULL; 00246 } 00247 if (config == NULL) { 00248 return NULL; 00249 } 00250 av_strlcatf(buff, size, "a=rtpmap:%d MPEG4-GENERIC/%d/%d\r\n" 00251 "a=fmtp:%d profile-level-id=1;" 00252 "mode=AAC-hbr;sizelength=13;indexlength=3;" 00253 "indexdeltalength=3%s\r\n", 00254 payload_type, c->sample_rate, c->channels, 00255 payload_type, config); 00256 break; 00257 case CODEC_ID_PCM_S16BE: 00258 if (payload_type >= RTP_PT_PRIVATE) 00259 av_strlcatf(buff, size, "a=rtpmap:%d L16/%d/%d\r\n", 00260 payload_type, 00261 c->sample_rate, c->channels); 00262 break; 00263 case CODEC_ID_PCM_MULAW: 00264 if (payload_type >= RTP_PT_PRIVATE) 00265 av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n", 00266 payload_type, 00267 c->sample_rate, c->channels); 00268 break; 00269 case CODEC_ID_PCM_ALAW: 00270 if (payload_type >= RTP_PT_PRIVATE) 00271 av_strlcatf(buff, size, "a=rtpmap:%d PCMA/%d/%d\r\n", 00272 payload_type, 00273 c->sample_rate, c->channels); 00274 break; 00275 case CODEC_ID_AMR_NB: 00276 av_strlcatf(buff, size, "a=rtpmap:%d AMR/%d/%d\r\n" 00277 "a=fmtp:%d octet-align=1\r\n", 00278 payload_type, c->sample_rate, c->channels, 00279 payload_type); 00280 break; 00281 case CODEC_ID_AMR_WB: 00282 av_strlcatf(buff, size, "a=rtpmap:%d AMR-WB/%d/%d\r\n" 00283 "a=fmtp:%d octet-align=1\r\n", 00284 payload_type, c->sample_rate, c->channels, 00285 payload_type); 00286 break; 00287 default: 00288 /* Nothing special to do here... */ 00289 break; 00290 } 00291 00292 av_free(config); 00293 00294 return buff; 00295 } 00296 00297 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, const char *dest_addr, int port, int ttl) 00298 { 00299 const char *type; 00300 int payload_type; 00301 00302 payload_type = ff_rtp_get_payload_type(c); 00303 if (payload_type < 0) { 00304 payload_type = RTP_PT_PRIVATE + (c->codec_type == AVMEDIA_TYPE_AUDIO); 00305 } 00306 00307 switch (c->codec_type) { 00308 case AVMEDIA_TYPE_VIDEO : type = "video" ; break; 00309 case AVMEDIA_TYPE_AUDIO : type = "audio" ; break; 00310 case AVMEDIA_TYPE_SUBTITLE: type = "text" ; break; 00311 default : type = "application"; break; 00312 } 00313 00314 av_strlcatf(buff, size, "m=%s %d RTP/AVP %d\r\n", type, port, payload_type); 00315 sdp_write_address(buff, size, dest_addr, ttl); 00316 if (c->bit_rate) { 00317 av_strlcatf(buff, size, "b=AS:%d\r\n", c->bit_rate / 1000); 00318 } 00319 00320 sdp_write_media_attributes(buff, size, c, payload_type); 00321 } 00322 00323 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) 00324 { 00325 AVMetadataTag *title = av_metadata_get(ac[0]->metadata, "title", NULL, 0); 00326 struct sdp_session_level s; 00327 int i, j, port, ttl; 00328 char dst[32]; 00329 00330 memset(buff, 0, size); 00331 memset(&s, 0, sizeof(struct sdp_session_level)); 00332 s.user = "-"; 00333 s.src_addr = "127.0.0.1"; /* FIXME: Properly set this */ 00334 s.name = title ? title->value : "No Name"; 00335 00336 port = 0; 00337 ttl = 0; 00338 if (n_files == 1) { 00339 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->filename); 00340 resolve_destination(dst, sizeof(dst)); 00341 if (dst[0]) { 00342 s.dst_addr = dst; 00343 s.ttl = ttl; 00344 } 00345 } 00346 sdp_write_header(buff, size, &s); 00347 00348 dst[0] = 0; 00349 for (i = 0; i < n_files; i++) { 00350 if (n_files != 1) { 00351 port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename); 00352 resolve_destination(dst, sizeof(dst)); 00353 } 00354 for (j = 0; j < ac[i]->nb_streams; j++) { 00355 ff_sdp_write_media(buff, size, 00356 ac[i]->streams[j]->codec, dst[0] ? dst : NULL, 00357 (port > 0) ? port + j * 2 : 0, ttl); 00358 if (port <= 0) { 00359 av_strlcatf(buff, size, 00360 "a=control:streamid=%d\r\n", i + j); 00361 } 00362 } 00363 } 00364 00365 return 0; 00366 } 00367 #else 00368 int avf_sdp_create(AVFormatContext *ac[], int n_files, char *buff, int size) 00369 { 00370 return AVERROR(ENOSYS); 00371 } 00372 00373 void ff_sdp_write_media(char *buff, int size, AVCodecContext *c, 00374 const char *dest_addr, int port, int ttl) 00375 { 00376 } 00377 #endif