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 int ret = ff_rtp_finalize_packet(pkt, &data->fragment, st->index);
00205 if (ret < 0) {
00206 av_log(ctx, AV_LOG_ERROR,
00207 "Error occurred when getting fragment buffer.");
00208 return ret;
00209 }
00210
00211 return 0;
00212 }
00213 }
00214
00215 return AVERROR(EAGAIN);
00216 }
00217
00221 static int get_base128(const uint8_t ** buf, const uint8_t * buf_end)
00222 {
00223 int n = 0;
00224 for (; *buf < buf_end; ++*buf) {
00225 n <<= 7;
00226 n += **buf & 0x7f;
00227 if (!(**buf & 0x80)) {
00228 ++*buf;
00229 return n;
00230 }
00231 }
00232 return 0;
00233 }
00234
00238 static int
00239 parse_packed_headers(const uint8_t * packed_headers,
00240 const uint8_t * packed_headers_end,
00241 AVCodecContext * codec, PayloadContext * xiph_data)
00242 {
00243
00244 unsigned num_packed, num_headers, length, length1, length2, extradata_alloc;
00245 uint8_t *ptr;
00246
00247 if (packed_headers_end - packed_headers < 9) {
00248 av_log(codec, AV_LOG_ERROR,
00249 "Invalid %td byte packed header.",
00250 packed_headers_end - packed_headers);
00251 return AVERROR_INVALIDDATA;
00252 }
00253
00254 num_packed = bytestream_get_be32(&packed_headers);
00255 xiph_data->ident = bytestream_get_be24(&packed_headers);
00256 length = bytestream_get_be16(&packed_headers);
00257 num_headers = get_base128(&packed_headers, packed_headers_end);
00258 length1 = get_base128(&packed_headers, packed_headers_end);
00259 length2 = get_base128(&packed_headers, packed_headers_end);
00260
00261 if (num_packed != 1 || num_headers > 3) {
00262 av_log(codec, AV_LOG_ERROR,
00263 "Unimplemented number of headers: %d packed headers, %d headers\n",
00264 num_packed, num_headers);
00265 return AVERROR_PATCHWELCOME;
00266 }
00267
00268 if (packed_headers_end - packed_headers != length ||
00269 length1 > length || length2 > length - length1) {
00270 av_log(codec, AV_LOG_ERROR,
00271 "Bad packed header lengths (%d,%d,%td,%d)\n", length1,
00272 length2, packed_headers_end - packed_headers, length);
00273 return AVERROR_INVALIDDATA;
00274 }
00275
00276
00277
00278
00279
00280 extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE;
00281
00282 ptr = codec->extradata = av_malloc(extradata_alloc);
00283 if (!ptr) {
00284 av_log(codec, AV_LOG_ERROR, "Out of memory\n");
00285 return AVERROR(ENOMEM);
00286 }
00287 *ptr++ = 2;
00288 ptr += av_xiphlacing(ptr, length1);
00289 ptr += av_xiphlacing(ptr, length2);
00290 memcpy(ptr, packed_headers, length);
00291 ptr += length;
00292 codec->extradata_size = ptr - codec->extradata;
00293
00294 memset(ptr, 0, extradata_alloc - codec->extradata_size);
00295
00296 return 0;
00297 }
00298
00299 static int xiph_parse_fmtp_pair(AVStream* stream,
00300 PayloadContext *xiph_data,
00301 char *attr, char *value)
00302 {
00303 AVCodecContext *codec = stream->codec;
00304 int result = 0;
00305
00306 if (!strcmp(attr, "sampling")) {
00307 if (!strcmp(value, "YCbCr-4:2:0")) {
00308 codec->pix_fmt = AV_PIX_FMT_YUV420P;
00309 } else if (!strcmp(value, "YCbCr-4:4:2")) {
00310 codec->pix_fmt = AV_PIX_FMT_YUV422P;
00311 } else if (!strcmp(value, "YCbCr-4:4:4")) {
00312 codec->pix_fmt = AV_PIX_FMT_YUV444P;
00313 } else {
00314 av_log(codec, AV_LOG_ERROR,
00315 "Unsupported pixel format %s\n", attr);
00316 return AVERROR_INVALIDDATA;
00317 }
00318 } else if (!strcmp(attr, "width")) {
00319
00320
00321 codec->width = atoi(value);
00322 return 0;
00323 } else if (!strcmp(attr, "height")) {
00324
00325
00326 codec->height = atoi(value);
00327 return 0;
00328 } else if (!strcmp(attr, "delivery-method")) {
00329
00330 return AVERROR_PATCHWELCOME;
00331 } else if (!strcmp(attr, "configuration-uri")) {
00332
00333
00334
00335 return AVERROR_PATCHWELCOME;
00336 } else if (!strcmp(attr, "configuration")) {
00337
00338
00339 uint8_t *decoded_packet = NULL;
00340 int packet_size;
00341 size_t decoded_alloc = strlen(value) / 4 * 3 + 4;
00342
00343 if (decoded_alloc <= INT_MAX) {
00344 decoded_packet = av_malloc(decoded_alloc);
00345 if (decoded_packet) {
00346 packet_size =
00347 av_base64_decode(decoded_packet, value, decoded_alloc);
00348
00349 result = parse_packed_headers
00350 (decoded_packet, decoded_packet + packet_size, codec,
00351 xiph_data);
00352 } else {
00353 av_log(codec, AV_LOG_ERROR,
00354 "Out of memory while decoding SDP configuration.\n");
00355 result = AVERROR(ENOMEM);
00356 }
00357 } else {
00358 av_log(codec, AV_LOG_ERROR, "Packet too large\n");
00359 result = AVERROR_INVALIDDATA;
00360 }
00361 av_free(decoded_packet);
00362 }
00363 return result;
00364 }
00365
00366 static int xiph_parse_sdp_line(AVFormatContext *s, int st_index,
00367 PayloadContext *data, const char *line)
00368 {
00369 const char *p;
00370
00371 if (st_index < 0)
00372 return 0;
00373
00374 if (av_strstart(line, "fmtp:", &p)) {
00375 return ff_parse_fmtp(s->streams[st_index], data, p,
00376 xiph_parse_fmtp_pair);
00377 }
00378
00379 return 0;
00380 }
00381
00382 RTPDynamicProtocolHandler ff_theora_dynamic_handler = {
00383 .enc_name = "theora",
00384 .codec_type = AVMEDIA_TYPE_VIDEO,
00385 .codec_id = AV_CODEC_ID_THEORA,
00386 .parse_sdp_a_line = xiph_parse_sdp_line,
00387 .alloc = xiph_new_context,
00388 .free = xiph_free_context,
00389 .parse_packet = xiph_handle_packet
00390 };
00391
00392 RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = {
00393 .enc_name = "vorbis",
00394 .codec_type = AVMEDIA_TYPE_AUDIO,
00395 .codec_id = AV_CODEC_ID_VORBIS,
00396 .parse_sdp_a_line = xiph_parse_sdp_line,
00397 .alloc = xiph_new_context,
00398 .free = xiph_free_context,
00399 .parse_packet = xiph_handle_packet
00400 };