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/avassert.h"
00031 #include "libavutil/avstring.h"
00032 #include "libavutil/base64.h"
00033 #include "libavcodec/bytestream.h"
00034
00035 #include "rtpdec.h"
00036 #include "rtpdec_formats.h"
00037
00041 struct PayloadContext {
00042 unsigned ident;
00043 uint32_t timestamp;
00044 AVIOContext* fragment;
00045 uint8_t *split_buf;
00046 int split_pos, split_buf_len, split_buf_size;
00047 int split_pkts;
00048 };
00049
00050 static PayloadContext *xiph_new_context(void)
00051 {
00052 return av_mallocz(sizeof(PayloadContext));
00053 }
00054
00055 static inline void free_fragment_if_needed(PayloadContext * data)
00056 {
00057 if (data->fragment) {
00058 uint8_t* p;
00059 avio_close_dyn_buf(data->fragment, &p);
00060 av_free(p);
00061 data->fragment = NULL;
00062 }
00063 }
00064
00065 static void xiph_free_context(PayloadContext * data)
00066 {
00067 free_fragment_if_needed(data);
00068 av_free(data->split_buf);
00069 av_free(data);
00070 }
00071
00072 static int xiph_handle_packet(AVFormatContext * ctx,
00073 PayloadContext * data,
00074 AVStream * st,
00075 AVPacket * pkt,
00076 uint32_t * timestamp,
00077 const uint8_t * buf, int len, int flags)
00078 {
00079
00080 int ident, fragmented, tdt, num_pkts, pkt_len;
00081
00082 if (!buf) {
00083 if (!data->split_buf || data->split_pos + 2 > data->split_buf_len ||
00084 data->split_pkts <= 0) {
00085 av_log(ctx, AV_LOG_ERROR, "No more data to return\n");
00086 return AVERROR_INVALIDDATA;
00087 }
00088 pkt_len = AV_RB16(data->split_buf + data->split_pos);
00089 data->split_pos += 2;
00090 if (data->split_pos + pkt_len > data->split_buf_len) {
00091 av_log(ctx, AV_LOG_ERROR, "Not enough data to return\n");
00092 return AVERROR_INVALIDDATA;
00093 }
00094 if (av_new_packet(pkt, pkt_len)) {
00095 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
00096 return AVERROR(ENOMEM);
00097 }
00098 pkt->stream_index = st->index;
00099 memcpy(pkt->data, data->split_buf + data->split_pos, pkt_len);
00100 data->split_pos += pkt_len;
00101 data->split_pkts--;
00102 return data->split_pkts > 0;
00103 }
00104
00105 if (len < 6) {
00106 av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len);
00107 return AVERROR_INVALIDDATA;
00108 }
00109
00110
00111 ident = AV_RB24(buf);
00112 fragmented = buf[3] >> 6;
00113 tdt = (buf[3] >> 4) & 3;
00114 num_pkts = buf[3] & 0xf;
00115 pkt_len = AV_RB16(buf + 4);
00116
00117 if (pkt_len > len - 6) {
00118 av_log(ctx, AV_LOG_ERROR,
00119 "Invalid packet length %d in %d byte packet\n", pkt_len,
00120 len);
00121 return AVERROR_INVALIDDATA;
00122 }
00123
00124 if (ident != data->ident) {
00125 av_log(ctx, AV_LOG_ERROR,
00126 "Unimplemented Xiph SDP configuration change detected\n");
00127 return AVERROR_PATCHWELCOME;
00128 }
00129
00130 if (tdt) {
00131 av_log(ctx, AV_LOG_ERROR,
00132 "Unimplemented RTP Xiph packet settings (%d,%d,%d)\n",
00133 fragmented, tdt, num_pkts);
00134 return AVERROR_PATCHWELCOME;
00135 }
00136
00137 buf += 6;
00138 len -= 6;
00139
00140 if (fragmented == 0) {
00141 if (av_new_packet(pkt, pkt_len)) {
00142 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
00143 return AVERROR(ENOMEM);
00144 }
00145 pkt->stream_index = st->index;
00146 memcpy(pkt->data, buf, pkt_len);
00147 buf += pkt_len;
00148 len -= pkt_len;
00149 num_pkts--;
00150
00151 if (num_pkts > 0) {
00152 if (len > data->split_buf_size || !data->split_buf) {
00153 av_freep(&data->split_buf);
00154 data->split_buf_size = 2 * len;
00155 data->split_buf = av_malloc(data->split_buf_size);
00156 if (!data->split_buf) {
00157 av_log(ctx, AV_LOG_ERROR, "Out of memory.\n");
00158 av_free_packet(pkt);
00159 return AVERROR(ENOMEM);
00160 }
00161 }
00162 memcpy(data->split_buf, buf, len);
00163 data->split_buf_len = len;
00164 data->split_pos = 0;
00165 data->split_pkts = num_pkts;
00166 return 1;
00167 }
00168
00169 return 0;
00170
00171 } else if (fragmented == 1) {
00172
00173 int res;
00174
00175
00176 free_fragment_if_needed(data);
00177
00178 if((res = avio_open_dyn_buf(&data->fragment)) < 0)
00179 return res;
00180
00181 avio_write(data->fragment, buf, pkt_len);
00182 data->timestamp = *timestamp;
00183
00184 } else {
00185 av_assert1(fragmented < 4);
00186 if (data->timestamp != *timestamp) {
00187
00188
00189 free_fragment_if_needed(data);
00190 av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n");
00191 return AVERROR_INVALIDDATA;
00192 }
00193 if (!data->fragment) {
00194 av_log(ctx, AV_LOG_WARNING,
00195 "Received packet without a start fragment; dropping.\n");
00196 return AVERROR(EAGAIN);
00197 }
00198
00199
00200 avio_write(data->fragment, buf, pkt_len);
00201
00202 if (fragmented == 3) {
00203
00204 av_init_packet(pkt);
00205 pkt->size = avio_close_dyn_buf(data->fragment, &pkt->data);
00206
00207 if (pkt->size < 0) {
00208 av_log(ctx, AV_LOG_ERROR,
00209 "Error occurred when getting fragment buffer.");
00210 return pkt->size;
00211 }
00212
00213 pkt->stream_index = st->index;
00214 pkt->destruct = av_destruct_packet;
00215
00216 data->fragment = NULL;
00217
00218 return 0;
00219 }
00220 }
00221
00222 return AVERROR(EAGAIN);
00223 }
00224
00228 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
00229 {
00230 int n = 0;
00231 for (; *buf < buf_end; ++*buf) {
00232 n <<= 7;
00233 n += **buf & 0x7f;
00234 if (!(**buf & 0x80)) {
00235 ++*buf;
00236 return n;
00237 }
00238 }
00239 return 0;
00240 }
00241
00245 static unsigned int
00246 parse_packed_headers(const uint8_t * packed_headers,
00247 const uint8_t * packed_headers_end,
00248 AVCodecContext * codec, PayloadContext * xiph_data)
00249 {
00250
00251 unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
00252 uint8_t *ptr;
00253
00254 if (packed_headers_end - packed_headers < 9) {
00255 av_log(codec, AV_LOG_ERROR,
00256 "Invalid %td byte packed header.",
00257 packed_headers_end - packed_headers);
00258 return AVERROR_INVALIDDATA;
00259 }
00260
00261 num_packed = bytestream_get_be32(&packed_headers);
00262 xiph_data->ident = bytestream_get_be24(&packed_headers);
00263 length = bytestream_get_be16(&packed_headers);
00264 num_headers = get_base128(&packed_headers, packed_headers_end);
00265 length1 = get_base128(&packed_headers, packed_headers_end);
00266 length2 = get_base128(&packed_headers, packed_headers_end);
00267
00268 if (num_packed != 1 || num_headers > 3) {
00269 av_log(codec, AV_LOG_ERROR,
00270 "Unimplemented number of headers: %d packed headers, %d headers\n",
00271 num_packed, num_headers);
00272 return AVERROR_PATCHWELCOME;
00273 }
00274
00275 if (packed_headers_end - packed_headers != length ||
00276 length1 > length || length2 > length - length1) {
00277 av_log(codec, AV_LOG_ERROR,
00278 "Bad packed header lengths (%d,%d,%td,%d)\n", length1,
00279 length2, packed_headers_end - packed_headers, length);
00280 return AVERROR_INVALIDDATA;
00281 }
00282
00283
00284
00285
00286
00287 extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
00288
00289 ptr = codec->extradata = av_malloc(extradata_alloc);
00290 if (!ptr) {
00291 av_log(codec, AV_LOG_ERROR, "Out of memory\n");
00292 return AVERROR(ENOMEM);
00293 }
00294 *ptr++ = 2;
00295 ptr += av_xiphlacing(ptr, length1);
00296 ptr += av_xiphlacing(ptr, length2);
00297 memcpy(ptr, packed_headers, length);
00298 ptr += length;
00299 codec->extradata_size = ptr - codec->extradata;
00300
00301 memset(ptr, 0, extradata_alloc - codec->extradata_size);
00302
00303 return 0;
00304 }
00305
00306 static int xiph_parse_fmtp_pair(AVStream* stream,
00307 PayloadContext *xiph_data,
00308 char *attr, char *value)
00309 {
00310 AVCodecContext *codec = stream->codec;
00311 int result = 0;
00312
00313 if (!strcmp(attr, "sampling")) {
00314 if (!strcmp(value, "YCbCr-4:2:0")) {
00315 codec->pix_fmt = PIX_FMT_YUV420P;
00316 } else if (!strcmp(value, "YCbCr-4:4:2")) {
00317 codec->pix_fmt = PIX_FMT_YUV422P;
00318 } else if (!strcmp(value, "YCbCr-4:4:4")) {
00319 codec->pix_fmt = PIX_FMT_YUV444P;
00320 } else {
00321 av_log(codec, AV_LOG_ERROR,
00322 "Unsupported pixel format %s\n", attr);
00323 return AVERROR_INVALIDDATA;
00324 }
00325 } else if (!strcmp(attr, "width")) {
00326
00327
00328 codec->width = atoi(value);
00329 return 0;
00330 } else if (!strcmp(attr, "height")) {
00331
00332
00333 codec->height = atoi(value);
00334 return 0;
00335 } else if (!strcmp(attr, "delivery-method")) {
00336
00337 return AVERROR_PATCHWELCOME;
00338 } else if (!strcmp(attr, "configuration-uri")) {
00339
00340
00341
00342 return AVERROR_PATCHWELCOME;
00343 } else if (!strcmp(attr, "configuration")) {
00344
00345
00346 uint8_t *decoded_packet = NULL;
00347 int packet_size;
00348 size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
00349
00350 if (decoded_alloc <= INT_MAX) {
00351 decoded_packet = av_malloc(decoded_alloc);
00352 if (decoded_packet) {
00353 packet_size =
00354 av_base64_decode(decoded_packet, value, decoded_alloc);
00355
00356 result = parse_packed_headers
00357 (decoded_packet, decoded_packet + packet_size, codec,
00358 xiph_data);
00359 } else {
00360 av_log(codec, AV_LOG_ERROR,
00361 "Out of memory while decoding SDP configuration.\n");
00362 result = AVERROR(ENOMEM);
00363 }
00364 } else {
00365 av_log(codec, AV_LOG_ERROR, "Packet too large\n");
00366 result = AVERROR_INVALIDDATA;
00367 }
00368 av_free(decoded_packet);
00369 }
00370 return result;
00371 }
00372
00373 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index,
00374 PayloadContext *data, const char *line)
00375 {
00376 const char *p;
00377
00378 if (st_index < 0)
00379 return 0;
00380
00381 if (av_strstart(line, "fmtp:", &p)) {
00382 return ff_parse_fmtp(s->streams[st_index], data, p,
00383 xiph_parse_fmtp_pair);
00384 }
00385
00386 return 0;
00387 }
00388
00389 RTPDynamicProtocolHandler ff_theora_dynamic_handler = {
00390 .enc_name = "theora",
00391 .codec_type = AVMEDIA_TYPE_VIDEO,
00392 .codec_id = AV_CODEC_ID_THEORA,
00393 .parse_sdp_a_line = xiph_parse_sdp_line,
00394 .alloc = xiph_new_context,
00395 .free = xiph_free_context,
00396 .parse_packet = xiph_handle_packet
00397 };
00398
00399 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = {
00400 .enc_name = "vorbis",
00401 .codec_type = AVMEDIA_TYPE_AUDIO,
00402 .codec_id = AV_CODEC_ID_VORBIS,
00403 .parse_sdp_a_line = xiph_parse_sdp_line,
00404 .alloc = xiph_new_context,
00405 .free = xiph_free_context,
00406 .parse_packet = xiph_handle_packet
00407 };