Libav
|
00001 /* 00002 * Xiph RTP Protocols 00003 * Copyright (c) 2009 Colin McQuillian 00004 * Copyright (c) 2010 Josh Allmann 00005 * 00006 * This file is part of FFmpeg. 00007 * 00008 * FFmpeg is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * FFmpeg is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with FFmpeg; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00030 #include "libavutil/avstring.h" 00031 #include "libavutil/base64.h" 00032 #include "libavcodec/bytestream.h" 00033 00034 #include <assert.h> 00035 00036 #include "rtpdec.h" 00037 #include "rtpdec_xiph.h" 00038 00042 struct PayloadContext { 00043 unsigned ident; 00044 uint32_t timestamp; 00045 ByteIOContext* fragment; 00046 }; 00047 00048 static PayloadContext *xiph_new_context(void) 00049 { 00050 return av_mallocz(sizeof(PayloadContext)); 00051 } 00052 00053 static inline void free_fragment_if_needed(PayloadContext * data) 00054 { 00055 if (data->fragment) { 00056 uint8_t* p; 00057 url_close_dyn_buf(data->fragment, &p); 00058 av_free(p); 00059 data->fragment = NULL; 00060 } 00061 } 00062 00063 static void xiph_free_context(PayloadContext * data) 00064 { 00065 free_fragment_if_needed(data); 00066 av_free(data); 00067 } 00068 00069 static int xiph_handle_packet(AVFormatContext * ctx, 00070 PayloadContext * data, 00071 AVStream * st, 00072 AVPacket * pkt, 00073 uint32_t * timestamp, 00074 const uint8_t * buf, int len, int flags) 00075 { 00076 00077 int ident, fragmented, tdt, num_pkts, pkt_len; 00078 00079 if (len < 6) { 00080 av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len); 00081 return AVERROR_INVALIDDATA; 00082 } 00083 00084 // read xiph rtp headers 00085 ident = AV_RB24(buf); 00086 fragmented = buf[3] >> 6; 00087 tdt = (buf[3] >> 4) & 3; 00088 num_pkts = buf[3] & 7; 00089 pkt_len = AV_RB16(buf + 4); 00090 00091 if (pkt_len > len - 6) { 00092 av_log(ctx, AV_LOG_ERROR, 00093 "Invalid packet length %d in %d byte packet\n", pkt_len, 00094 len); 00095 return AVERROR_INVALIDDATA; 00096 } 00097 00098 if (ident != data->ident) { 00099 av_log(ctx, AV_LOG_ERROR, 00100 "Unimplemented Xiph SDP configuration change detected\n"); 00101 return AVERROR_PATCHWELCOME; 00102 } 00103 00104 if (tdt) { 00105 av_log(ctx, AV_LOG_ERROR, 00106 "Unimplemented RTP Xiph packet settings (%d,%d,%d)\n", 00107 fragmented, tdt, num_pkts); 00108 return AVERROR_PATCHWELCOME; 00109 } 00110 00111 buf += 6; // move past header bits 00112 len -= 6; 00113 00114 if (fragmented == 0) { 00115 // whole frame(s) 00116 int i, data_len, write_len; 00117 buf -= 2; 00118 len += 2; 00119 00120 // fast first pass to calculate total length 00121 for (i = 0, data_len = 0; (i < num_pkts) && (len >= 2); i++) { 00122 int off = data_len + (i << 1); 00123 pkt_len = AV_RB16(buf + off); 00124 data_len += pkt_len; 00125 len -= pkt_len + 2; 00126 } 00127 00128 if (len < 0 || i < num_pkts) { 00129 av_log(ctx, AV_LOG_ERROR, 00130 "Bad packet: %d bytes left at frame %d of %d\n", 00131 len, i, num_pkts); 00132 return AVERROR_INVALIDDATA; 00133 } 00134 00135 if (av_new_packet(pkt, data_len)) { 00136 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 00137 return AVERROR(ENOMEM); 00138 } 00139 pkt->stream_index = st->index; 00140 00141 // concatenate frames 00142 for (i = 0, write_len = 0; write_len < data_len; i++) { 00143 pkt_len = AV_RB16(buf); 00144 buf += 2; 00145 memcpy(pkt->data + write_len, buf, pkt_len); 00146 write_len += pkt_len; 00147 buf += pkt_len; 00148 } 00149 assert(write_len == data_len); 00150 00151 return 0; 00152 00153 } else if (fragmented == 1) { 00154 // start of xiph data fragment 00155 int res; 00156 00157 // end packet has been lost somewhere, so drop buffered data 00158 free_fragment_if_needed(data); 00159 00160 if((res = url_open_dyn_buf(&data->fragment)) < 0) 00161 return res; 00162 00163 put_buffer(data->fragment, buf, pkt_len); 00164 data->timestamp = *timestamp; 00165 00166 } else { 00167 assert(fragmented < 4); 00168 if (data->timestamp != *timestamp) { 00169 // skip if fragmented timestamp is incorrect; 00170 // a start packet has been lost somewhere 00171 free_fragment_if_needed(data); 00172 av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n"); 00173 return AVERROR_INVALIDDATA; 00174 } 00175 00176 // copy data to fragment buffer 00177 put_buffer(data->fragment, buf, pkt_len); 00178 00179 if (fragmented == 3) { 00180 // end of xiph data packet 00181 uint8_t* xiph_data; 00182 int frame_size = url_close_dyn_buf(data->fragment, &xiph_data); 00183 00184 if (frame_size < 0) { 00185 av_log(ctx, AV_LOG_ERROR, 00186 "Error occurred when getting fragment buffer."); 00187 return frame_size; 00188 } 00189 00190 if (av_new_packet(pkt, frame_size)) { 00191 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); 00192 return AVERROR(ENOMEM); 00193 } 00194 00195 memcpy(pkt->data, xiph_data, frame_size); 00196 pkt->stream_index = st->index; 00197 00198 av_free(xiph_data); 00199 data->fragment = NULL; 00200 00201 return 0; 00202 } 00203 } 00204 00205 return AVERROR(EAGAIN); 00206 } 00207 00211 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end) 00212 { 00213 int n = 0; 00214 for (; *buf < buf_end; ++*buf) { 00215 n <<= 7; 00216 n += **buf & 0x7f; 00217 if (!(**buf & 0x80)) { 00218 ++*buf; 00219 return n; 00220 } 00221 } 00222 return 0; 00223 } 00224 00228 static unsigned int 00229 parse_packed_headers(const uint8_t * packed_headers, 00230 const uint8_t * packed_headers_end, 00231 AVCodecContext * codec, PayloadContext * xiph_data) 00232 { 00233 00234 unsigned num_packed, num_headers, length, length1, length2, extradata_alloc; 00235 uint8_t *ptr; 00236 00237 if (packed_headers_end - packed_headers < 9) { 00238 av_log(codec, AV_LOG_ERROR, 00239 "Invalid %d byte packed header.", 00240 packed_headers_end - packed_headers); 00241 return AVERROR_INVALIDDATA; 00242 } 00243 00244 num_packed = bytestream_get_be32(&packed_headers); 00245 xiph_data->ident = bytestream_get_be24(&packed_headers); 00246 length = bytestream_get_be16(&packed_headers); 00247 num_headers = get_base128(&packed_headers, packed_headers_end); 00248 length1 = get_base128(&packed_headers, packed_headers_end); 00249 length2 = get_base128(&packed_headers, packed_headers_end); 00250 00251 if (num_packed != 1 || num_headers > 3) { 00252 av_log(codec, AV_LOG_ERROR, 00253 "Unimplemented number of headers: %d packed headers, %d headers\n", 00254 num_packed, num_headers); 00255 return AVERROR_PATCHWELCOME; 00256 } 00257 00258 if (packed_headers_end - packed_headers != length || 00259 length1 > length || length2 > length - length1) { 00260 av_log(codec, AV_LOG_ERROR, 00261 "Bad packed header lengths (%d,%d,%d,%d)\n", length1, 00262 length2, packed_headers_end - packed_headers, length); 00263 return AVERROR_INVALIDDATA; 00264 } 00265 00266 /* allocate extra space: 00267 * -- length/255 +2 for xiphlacing 00268 * -- one for the '2' marker 00269 * -- FF_INPUT_BUFFER_PADDING_SIZE required */ 00270 extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE; 00271 00272 ptr = codec->extradata = av_malloc(extradata_alloc); 00273 if (!ptr) { 00274 av_log(codec, AV_LOG_ERROR, "Out of memory\n"); 00275 return AVERROR(ENOMEM); 00276 } 00277 *ptr++ = 2; 00278 ptr += av_xiphlacing(ptr, length1); 00279 ptr += av_xiphlacing(ptr, length2); 00280 memcpy(ptr, packed_headers, length); 00281 ptr += length; 00282 codec->extradata_size = ptr - codec->extradata; 00283 // clear out remaining parts of the buffer 00284 memset(ptr, 0, extradata_alloc - codec->extradata_size); 00285 00286 return 0; 00287 } 00288 00289 static int xiph_parse_fmtp_pair(AVCodecContext * codec, 00290 PayloadContext *xiph_data, 00291 char *attr, char *value) 00292 { 00293 int result = 0; 00294 00295 if (!strcmp(attr, "sampling")) { 00296 return AVERROR_PATCHWELCOME; 00297 } else if (!strcmp(attr, "width")) { 00298 /* This is an integer between 1 and 1048561 00299 * and MUST be in multiples of 16. */ 00300 codec->width = atoi(value); 00301 return 0; 00302 } else if (!strcmp(attr, "height")) { 00303 /* This is an integer between 1 and 1048561 00304 * and MUST be in multiples of 16. */ 00305 codec->height = atoi(value); 00306 return 0; 00307 } else if (!strcmp(attr, "delivery-method")) { 00308 /* Possible values are: inline, in_band, out_band/specific_name. */ 00309 return AVERROR_PATCHWELCOME; 00310 } else if (!strcmp(attr, "configuration-uri")) { 00311 /* NOTE: configuration-uri is supported only under 2 conditions: 00312 *--after the delivery-method tag 00313 * --with a delivery-method value of out_band */ 00314 return AVERROR_PATCHWELCOME; 00315 } else if (!strcmp(attr, "configuration")) { 00316 /* NOTE: configuration is supported only AFTER the delivery-method tag 00317 * The configuration value is a base64 encoded packed header */ 00318 uint8_t *decoded_packet = NULL; 00319 int packet_size; 00320 size_t decoded_alloc = strlen(value) / 4 * 3 + 4; 00321 00322 if (decoded_alloc <= INT_MAX) { 00323 decoded_packet = av_malloc(decoded_alloc); 00324 if (decoded_packet) { 00325 packet_size = 00326 av_base64_decode(decoded_packet, value, decoded_alloc); 00327 00328 result = parse_packed_headers 00329 (decoded_packet, decoded_packet + packet_size, codec, 00330 xiph_data); 00331 } else { 00332 av_log(codec, AV_LOG_ERROR, 00333 "Out of memory while decoding SDP configuration.\n"); 00334 result = AVERROR(ENOMEM); 00335 } 00336 } else { 00337 av_log(codec, AV_LOG_ERROR, "Packet too large\n"); 00338 result = AVERROR_INVALIDDATA; 00339 } 00340 av_free(decoded_packet); 00341 } 00342 return result; 00343 } 00344 00345 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index, 00346 PayloadContext *data, const char *line) 00347 { 00348 const char *p; 00349 char *value; 00350 char attr[25]; 00351 int value_size = strlen(line), attr_size = sizeof(attr), res = 0; 00352 AVCodecContext* codec = s->streams[st_index]->codec; 00353 00354 assert(data); 00355 00356 if (!(value = av_malloc(value_size))) { 00357 av_log(codec, AV_LOG_ERROR, "Out of memory\n"); 00358 return AVERROR(ENOMEM); 00359 } 00360 00361 if (av_strstart(line, "fmtp:", &p)) { 00362 // remove protocol identifier 00363 while (*p && *p == ' ') p++; // strip spaces 00364 while (*p && *p != ' ') p++; // eat protocol identifier 00365 while (*p && *p == ' ') p++; // strip trailing spaces 00366 00367 while (ff_rtsp_next_attr_and_value(&p, 00368 attr, attr_size, 00369 value, value_size)) { 00370 res = xiph_parse_fmtp_pair(codec, data, attr, value); 00371 if (res < 0 && res != AVERROR_PATCHWELCOME) 00372 return res; 00373 } 00374 } 00375 00376 av_free(value); 00377 return 0; 00378 } 00379 00380 RTPDynamicProtocolHandler ff_theora_dynamic_handler = { 00381 .enc_name = "theora", 00382 .codec_type = AVMEDIA_TYPE_VIDEO, 00383 .codec_id = CODEC_ID_THEORA, 00384 .parse_sdp_a_line = xiph_parse_sdp_line, 00385 .open = xiph_new_context, 00386 .close = xiph_free_context, 00387 .parse_packet = xiph_handle_packet 00388 }; 00389 00390 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { 00391 .enc_name = "vorbis", 00392 .codec_type = AVMEDIA_TYPE_AUDIO, 00393 .codec_id = CODEC_ID_VORBIS, 00394 .parse_sdp_a_line = xiph_parse_sdp_line, 00395 .open = xiph_new_context, 00396 .close = xiph_free_context, 00397 .parse_packet = xiph_handle_packet 00398 };