00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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;
00112 len -= 6;
00113
00114 if (fragmented == 0) {
00115
00116 int i, data_len, write_len;
00117 buf -= 2;
00118 len += 2;
00119
00120
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
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
00155 int res;
00156
00157
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
00170
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
00177 put_buffer(data->fragment, buf, pkt_len);
00178
00179 if (fragmented == 3) {
00180
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
00267
00268
00269
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
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
00299
00300 codec->width = atoi(value);
00301 return 0;
00302 } else if (!strcmp(attr, "height")) {
00303
00304
00305 codec->height = atoi(value);
00306 return 0;
00307 } else if (!strcmp(attr, "delivery-method")) {
00308
00309 return AVERROR_PATCHWELCOME;
00310 } else if (!strcmp(attr, "configuration-uri")) {
00311
00312
00313
00314 return AVERROR_PATCHWELCOME;
00315 } else if (!strcmp(attr, "configuration")) {
00316
00317
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
00363 while (*p && *p == ' ') p++;
00364 while (*p && *p != ' ') p++;
00365 while (*p && *p == ' ') p++;
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 };