# HG changeset patch # User rbultje # Date 1270158056 0 # Node ID e3b4d71816067e359d982a4c0d8aa1f88e359888 # Parent 6cc73b15aa2820b23a63bf5f5a7ea1b104ef7177 Rename rtpdec_theora.[ch] to rtpdec_xiph.[ch], as a preparation for merging the Vorbis / theora depacketizers. Patch by Josh Allmann . diff -r 6cc73b15aa28 -r e3b4d7181606 Makefile --- a/Makefile Thu Apr 01 12:09:33 2010 +0000 +++ b/Makefile Thu Apr 01 21:40:56 2010 +0000 @@ -225,8 +225,8 @@ rtpdec_asf.o \ rtpdec_h263.o \ rtpdec_h264.o \ - rtpdec_theora.o \ - rtpdec_vorbis.o + rtpdec_vorbis.o \ + rtpdec_xiph.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o OBJS-$(CONFIG_SHORTEN_DEMUXER) += raw.o id3v2.o OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o diff -r 6cc73b15aa28 -r e3b4d7181606 rtpdec.c --- a/rtpdec.c Thu Apr 01 12:09:33 2010 +0000 +++ b/rtpdec.c Thu Apr 01 21:40:56 2010 +0000 @@ -34,8 +34,7 @@ #include "rtpdec_asf.h" #include "rtpdec_h263.h" #include "rtpdec_h264.h" -#include "rtpdec_vorbis.h" -#include "rtpdec_theora.h" +#include "rtpdec_xiph.h" //#define DEBUG diff -r 6cc73b15aa28 -r e3b4d7181606 rtpdec_theora.c --- a/rtpdec_theora.c Thu Apr 01 12:09:33 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -/* - * RTP Theora Protocol - * Copyright (c) 2010 Josh Allmann - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file libavformat/rtpdec_theora.c - * @brief Theora / RTP Code - * @author Josh Allmann - */ - -#include "libavutil/avstring.h" -#include "libavutil/base64.h" -#include "libavcodec/bytestream.h" - -#include - -#include "rtpdec.h" -#include "rtpdec_theora.h" - -/** - * RTP/Theora specific private data. - */ -struct PayloadContext { - unsigned ident; ///< 24-bit stream configuration identifier - uint32_t timestamp; - ByteIOContext* fragment; ///< buffer for split payloads -}; - -static PayloadContext *theora_new_context(void) -{ - return av_mallocz(sizeof(PayloadContext)); -} - -static inline void free_fragment_if_needed(PayloadContext * data) -{ - if (data->fragment) { - uint8_t* p; - url_close_dyn_buf(data->fragment, &p); - av_free(p); - data->fragment = NULL; - } -} - -static void theora_free_context(PayloadContext * data) -{ - free_fragment_if_needed(data); - av_free(data); -} - -static int theora_handle_packet(AVFormatContext * ctx, - PayloadContext * data, - AVStream * st, - AVPacket * pkt, - uint32_t * timestamp, - const uint8_t * buf, int len, int flags) -{ - - int ident, fragmented, tdt, num_pkts, pkt_len; - - if (len < 6) { - av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len); - return AVERROR_INVALIDDATA; - } - - // read theora rtp headers - ident = AV_RB24(buf); - fragmented = buf[3] >> 6; - tdt = (buf[3] >> 4) & 3; - num_pkts = buf[3] & 7; - pkt_len = AV_RB16(buf + 4); - - if (pkt_len > len - 6) { - av_log(ctx, AV_LOG_ERROR, - "Invalid packet length %d in %d byte packet\n", pkt_len, - len); - return AVERROR_INVALIDDATA; - } - - if (ident != data->ident) { - av_log(ctx, AV_LOG_ERROR, - "Unimplemented Theora SDP configuration change detected\n"); - return AVERROR_PATCHWELCOME; - } - - if (tdt) { - av_log(ctx, AV_LOG_ERROR, - "Unimplemented RTP Theora packet settings (%d,%d,%d)\n", - fragmented, tdt, num_pkts); - return AVERROR_PATCHWELCOME; - } - - buf += 6; // move past header bits - len -= 6; - - if (fragmented == 0) { - // whole frame(s) - int i, data_len, write_len; - buf -= 2; - len += 2; - - // fast first pass to calculate total length - for (i = 0, data_len = 0; (i < num_pkts) && (len >= 2); i++) { - int off = data_len + (i << 1); - pkt_len = AV_RB16(buf + off); - data_len += pkt_len; - len -= pkt_len + 2; - } - - if (len < 0 || i < num_pkts) { - av_log(ctx, AV_LOG_ERROR, - "Bad packet: %d bytes left at frame %d of %d\n", - len, i, num_pkts); - return AVERROR_INVALIDDATA; - } - - if (av_new_packet(pkt, data_len)) { - av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); - return AVERROR_NOMEM; - } - pkt->stream_index = st->index; - - // concatenate frames - for (i = 0, write_len = 0; write_len < data_len; i++) { - pkt_len = AV_RB16(buf); - buf += 2; - memcpy(pkt->data + write_len, buf, pkt_len); - write_len += pkt_len; - buf += pkt_len; - } - assert(write_len == data_len); - - return 0; - - } else if (fragmented == 1) { - // start of theora data fragment - int res; - - // end packet has been lost somewhere, so drop buffered data - free_fragment_if_needed(data); - - if((res = url_open_dyn_buf(&data->fragment)) < 0) - return res; - - put_buffer(data->fragment, buf, pkt_len); - data->timestamp = *timestamp; - - } else { - assert(fragmented < 4); - if (data->timestamp != *timestamp) { - // skip if fragmented timestamp is incorrect; - // a start packet has been lost somewhere - free_fragment_if_needed(data); - av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n"); - return AVERROR_INVALIDDATA; - } - - // copy data to fragment buffer - put_buffer(data->fragment, buf, pkt_len); - - if (fragmented == 3) { - // end of theora data packet - uint8_t* theora_data; - int frame_size = url_close_dyn_buf(data->fragment, &theora_data); - - if (frame_size < 0) { - av_log(ctx, AV_LOG_ERROR, - "Error occurred when getting fragment buffer."); - return frame_size; - } - - if (av_new_packet(pkt, frame_size)) { - av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); - return AVERROR_NOMEM; - } - - memcpy(pkt->data, theora_data, frame_size); - pkt->stream_index = st->index; - - av_free(theora_data); - data->fragment = NULL; - - return 0; - } - } - - return AVERROR(EAGAIN); -} - -/** - * Length encoding described in RFC5215 section 3.1.1. - */ -static int get_base128(const uint8_t ** buf, const uint8_t * buf_end) -{ - int n = 0; - for (; *buf < buf_end; ++*buf) { - n <<= 7; - n += **buf & 0x7f; - if (!(**buf & 0x80)) { - ++*buf; - return n; - } - } - return 0; -} - -/** - * Based off parse_packed_headers in Vorbis RTP - */ -static unsigned int -parse_packed_headers(const uint8_t * packed_headers, - const uint8_t * packed_headers_end, - AVCodecContext * codec, PayloadContext * theora_data) -{ - - unsigned num_packed, num_headers, length, length1, length2, extradata_alloc; - uint8_t *ptr; - - if (packed_headers_end - packed_headers < 9) { - av_log(codec, AV_LOG_ERROR, - "Invalid %d byte packed header.", - packed_headers_end - packed_headers); - return AVERROR_INVALIDDATA; - } - - num_packed = bytestream_get_be32(&packed_headers); - theora_data->ident = bytestream_get_be24(&packed_headers); - length = bytestream_get_be16(&packed_headers); - num_headers = get_base128(&packed_headers, packed_headers_end); - length1 = get_base128(&packed_headers, packed_headers_end); - length2 = get_base128(&packed_headers, packed_headers_end); - - if (num_packed != 1 || num_headers > 3) { - av_log(codec, AV_LOG_ERROR, - "Unimplemented number of headers: %d packed headers, %d headers\n", - num_packed, num_headers); - return AVERROR_PATCHWELCOME; - } - - if (packed_headers_end - packed_headers != length || - length1 > length || length2 > length - length1) { - av_log(codec, AV_LOG_ERROR, - "Bad packed header lengths (%d,%d,%d,%d)\n", length1, - length2, packed_headers_end - packed_headers, length); - return AVERROR_INVALIDDATA; - } - - /* allocate extra space: - * -- length/255 +2 for xiphlacing - * -- one for the '2' marker - * -- FF_INPUT_BUFFER_PADDING_SIZE required */ - extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE; - - ptr = codec->extradata = av_malloc(extradata_alloc); - if (!ptr) { - av_log(codec, AV_LOG_ERROR, "Out of memory\n"); - return AVERROR_NOMEM; - } - *ptr++ = 2; - ptr += av_xiphlacing(ptr, length1); - ptr += av_xiphlacing(ptr, length2); - memcpy(ptr, packed_headers, length); - ptr += length; - codec->extradata_size = ptr - codec->extradata; - // clear out remaining parts of the buffer - memset(ptr, 0, extradata_alloc - codec->extradata_size); - - return 0; -} - -static int theora_parse_fmtp_pair(AVCodecContext * codec, - PayloadContext *theora_data, - char *attr, char *value) -{ - int result = 0; - - if (!strcmp(attr, "sampling")) { - return AVERROR_PATCHWELCOME; - } else if (!strcmp(attr, "width")) { - /* This is an integer between 1 and 1048561 - * and MUST be in multiples of 16. */ - codec->width = atoi(value); - return 0; - } else if (!strcmp(attr, "height")) { - /* This is an integer between 1 and 1048561 - * and MUST be in multiples of 16. */ - codec->height = atoi(value); - return 0; - } else if (!strcmp(attr, "delivery-method")) { - /* Possible values are: inline, in_band, out_band/specific_name. */ - return AVERROR_PATCHWELCOME; - } else if (!strcmp(attr, "configuration-uri")) { - /* NOTE: configuration-uri is supported only under 2 conditions: - *--after the delivery-method tag - * --with a delivery-method value of out_band */ - return AVERROR_PATCHWELCOME; - } else if (!strcmp(attr, "configuration")) { - /* NOTE: configuration is supported only AFTER the delivery-method tag - * The configuration value is a base64 encoded packed header */ - uint8_t *decoded_packet = NULL; - int packet_size; - size_t decoded_alloc = strlen(value) / 4 * 3 + 4; - - if (decoded_alloc <= INT_MAX) { - decoded_packet = av_malloc(decoded_alloc); - if (decoded_packet) { - packet_size = - av_base64_decode(decoded_packet, value, decoded_alloc); - - result = parse_packed_headers - (decoded_packet, decoded_packet + packet_size, codec, - theora_data); - } else { - av_log(codec, AV_LOG_ERROR, - "Out of memory while decoding SDP configuration.\n"); - result = AVERROR_NOMEM; - } - } else { - av_log(codec, AV_LOG_ERROR, "Packet too large\n"); - result = AVERROR_INVALIDDATA; - } - av_free(decoded_packet); - } - return result; -} - -static int theora_parse_sdp_line(AVFormatContext *s, int st_index, - PayloadContext *data, const char *line) -{ - const char *p; - char *value; - char attr[25]; - int value_size = strlen(line), attr_size = sizeof(attr), res = 0; - AVCodecContext* codec = s->streams[st_index]->codec; - - assert(codec->id == CODEC_ID_THEORA); - assert(data); - - if (!(value = av_malloc(value_size))) { - av_log(codec, AV_LOG_ERROR, "Out of memory\n"); - return AVERROR_NOMEM; - } - - if (av_strstart(line, "fmtp:", &p)) { - // remove protocol identifier - while (*p && *p == ' ') p++; // strip spaces - while (*p && *p != ' ') p++; // eat protocol identifier - while (*p && *p == ' ') p++; // strip trailing spaces - - while (ff_rtsp_next_attr_and_value(&p, - attr, attr_size, - value, value_size)) { - res = theora_parse_fmtp_pair(codec, data, attr, value); - if (res < 0 && res != AVERROR_PATCHWELCOME) - return res; - } - } - - av_free(value); - return 0; -} - -RTPDynamicProtocolHandler ff_theora_dynamic_handler = { - .enc_name = "theora", - .codec_type = AVMEDIA_TYPE_VIDEO, - .codec_id = CODEC_ID_THEORA, - .parse_sdp_a_line = theora_parse_sdp_line, - .open = theora_new_context, - .close = theora_free_context, - .parse_packet = theora_handle_packet -}; diff -r 6cc73b15aa28 -r e3b4d7181606 rtpdec_theora.h --- a/rtpdec_theora.h Thu Apr 01 12:09:33 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * RTP Theora Protocol. - * Based off RFC 5215 (Vorbis RTP) and the Theora RTP draft. - * Copyright (c) 2010 Josh Allmann - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFORMAT_RTPDEC_THEORA_H -#define AVFORMAT_RTPDEC_THEORA_H - -#include "libavcodec/avcodec.h" -#include "rtpdec.h" - -/** - * Theora RTP callbacks. - */ -extern RTPDynamicProtocolHandler ff_theora_dynamic_handler; - -#endif /* AVFORMAT_RTPDEC_THEORA_H */ diff -r 6cc73b15aa28 -r e3b4d7181606 rtpdec_xiph.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rtpdec_xiph.c Thu Apr 01 21:40:56 2010 +0000 @@ -0,0 +1,387 @@ +/* + * RTP Theora Protocol + * Copyright (c) 2010 Josh Allmann + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file libavformat/rtpdec_theora.c + * @brief Theora / RTP Code + * @author Josh Allmann + */ + +#include "libavutil/avstring.h" +#include "libavutil/base64.h" +#include "libavcodec/bytestream.h" + +#include + +#include "rtpdec.h" +#include "rtpdec_xiph.h" + +/** + * RTP/Theora specific private data. + */ +struct PayloadContext { + unsigned ident; ///< 24-bit stream configuration identifier + uint32_t timestamp; + ByteIOContext* fragment; ///< buffer for split payloads +}; + +static PayloadContext *theora_new_context(void) +{ + return av_mallocz(sizeof(PayloadContext)); +} + +static inline void free_fragment_if_needed(PayloadContext * data) +{ + if (data->fragment) { + uint8_t* p; + url_close_dyn_buf(data->fragment, &p); + av_free(p); + data->fragment = NULL; + } +} + +static void theora_free_context(PayloadContext * data) +{ + free_fragment_if_needed(data); + av_free(data); +} + +static int theora_handle_packet(AVFormatContext * ctx, + PayloadContext * data, + AVStream * st, + AVPacket * pkt, + uint32_t * timestamp, + const uint8_t * buf, int len, int flags) +{ + + int ident, fragmented, tdt, num_pkts, pkt_len; + + if (len < 6) { + av_log(ctx, AV_LOG_ERROR, "Invalid %d byte packet\n", len); + return AVERROR_INVALIDDATA; + } + + // read theora rtp headers + ident = AV_RB24(buf); + fragmented = buf[3] >> 6; + tdt = (buf[3] >> 4) & 3; + num_pkts = buf[3] & 7; + pkt_len = AV_RB16(buf + 4); + + if (pkt_len > len - 6) { + av_log(ctx, AV_LOG_ERROR, + "Invalid packet length %d in %d byte packet\n", pkt_len, + len); + return AVERROR_INVALIDDATA; + } + + if (ident != data->ident) { + av_log(ctx, AV_LOG_ERROR, + "Unimplemented Theora SDP configuration change detected\n"); + return AVERROR_PATCHWELCOME; + } + + if (tdt) { + av_log(ctx, AV_LOG_ERROR, + "Unimplemented RTP Theora packet settings (%d,%d,%d)\n", + fragmented, tdt, num_pkts); + return AVERROR_PATCHWELCOME; + } + + buf += 6; // move past header bits + len -= 6; + + if (fragmented == 0) { + // whole frame(s) + int i, data_len, write_len; + buf -= 2; + len += 2; + + // fast first pass to calculate total length + for (i = 0, data_len = 0; (i < num_pkts) && (len >= 2); i++) { + int off = data_len + (i << 1); + pkt_len = AV_RB16(buf + off); + data_len += pkt_len; + len -= pkt_len + 2; + } + + if (len < 0 || i < num_pkts) { + av_log(ctx, AV_LOG_ERROR, + "Bad packet: %d bytes left at frame %d of %d\n", + len, i, num_pkts); + return AVERROR_INVALIDDATA; + } + + if (av_new_packet(pkt, data_len)) { + av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); + return AVERROR_NOMEM; + } + pkt->stream_index = st->index; + + // concatenate frames + for (i = 0, write_len = 0; write_len < data_len; i++) { + pkt_len = AV_RB16(buf); + buf += 2; + memcpy(pkt->data + write_len, buf, pkt_len); + write_len += pkt_len; + buf += pkt_len; + } + assert(write_len == data_len); + + return 0; + + } else if (fragmented == 1) { + // start of theora data fragment + int res; + + // end packet has been lost somewhere, so drop buffered data + free_fragment_if_needed(data); + + if((res = url_open_dyn_buf(&data->fragment)) < 0) + return res; + + put_buffer(data->fragment, buf, pkt_len); + data->timestamp = *timestamp; + + } else { + assert(fragmented < 4); + if (data->timestamp != *timestamp) { + // skip if fragmented timestamp is incorrect; + // a start packet has been lost somewhere + free_fragment_if_needed(data); + av_log(ctx, AV_LOG_ERROR, "RTP timestamps don't match!\n"); + return AVERROR_INVALIDDATA; + } + + // copy data to fragment buffer + put_buffer(data->fragment, buf, pkt_len); + + if (fragmented == 3) { + // end of theora data packet + uint8_t* theora_data; + int frame_size = url_close_dyn_buf(data->fragment, &theora_data); + + if (frame_size < 0) { + av_log(ctx, AV_LOG_ERROR, + "Error occurred when getting fragment buffer."); + return frame_size; + } + + if (av_new_packet(pkt, frame_size)) { + av_log(ctx, AV_LOG_ERROR, "Out of memory.\n"); + return AVERROR_NOMEM; + } + + memcpy(pkt->data, theora_data, frame_size); + pkt->stream_index = st->index; + + av_free(theora_data); + data->fragment = NULL; + + return 0; + } + } + + return AVERROR(EAGAIN); +} + +/** + * Length encoding described in RFC5215 section 3.1.1. + */ +static int get_base128(const uint8_t ** buf, const uint8_t * buf_end) +{ + int n = 0; + for (; *buf < buf_end; ++*buf) { + n <<= 7; + n += **buf & 0x7f; + if (!(**buf & 0x80)) { + ++*buf; + return n; + } + } + return 0; +} + +/** + * Based off parse_packed_headers in Vorbis RTP + */ +static unsigned int +parse_packed_headers(const uint8_t * packed_headers, + const uint8_t * packed_headers_end, + AVCodecContext * codec, PayloadContext * theora_data) +{ + + unsigned num_packed, num_headers, length, length1, length2, extradata_alloc; + uint8_t *ptr; + + if (packed_headers_end - packed_headers < 9) { + av_log(codec, AV_LOG_ERROR, + "Invalid %d byte packed header.", + packed_headers_end - packed_headers); + return AVERROR_INVALIDDATA; + } + + num_packed = bytestream_get_be32(&packed_headers); + theora_data->ident = bytestream_get_be24(&packed_headers); + length = bytestream_get_be16(&packed_headers); + num_headers = get_base128(&packed_headers, packed_headers_end); + length1 = get_base128(&packed_headers, packed_headers_end); + length2 = get_base128(&packed_headers, packed_headers_end); + + if (num_packed != 1 || num_headers > 3) { + av_log(codec, AV_LOG_ERROR, + "Unimplemented number of headers: %d packed headers, %d headers\n", + num_packed, num_headers); + return AVERROR_PATCHWELCOME; + } + + if (packed_headers_end - packed_headers != length || + length1 > length || length2 > length - length1) { + av_log(codec, AV_LOG_ERROR, + "Bad packed header lengths (%d,%d,%d,%d)\n", length1, + length2, packed_headers_end - packed_headers, length); + return AVERROR_INVALIDDATA; + } + + /* allocate extra space: + * -- length/255 +2 for xiphlacing + * -- one for the '2' marker + * -- FF_INPUT_BUFFER_PADDING_SIZE required */ + extradata_alloc = length + length/255 + 3 + FF_INPUT_BUFFER_PADDING_SIZE; + + ptr = codec->extradata = av_malloc(extradata_alloc); + if (!ptr) { + av_log(codec, AV_LOG_ERROR, "Out of memory\n"); + return AVERROR_NOMEM; + } + *ptr++ = 2; + ptr += av_xiphlacing(ptr, length1); + ptr += av_xiphlacing(ptr, length2); + memcpy(ptr, packed_headers, length); + ptr += length; + codec->extradata_size = ptr - codec->extradata; + // clear out remaining parts of the buffer + memset(ptr, 0, extradata_alloc - codec->extradata_size); + + return 0; +} + +static int theora_parse_fmtp_pair(AVCodecContext * codec, + PayloadContext *theora_data, + char *attr, char *value) +{ + int result = 0; + + if (!strcmp(attr, "sampling")) { + return AVERROR_PATCHWELCOME; + } else if (!strcmp(attr, "width")) { + /* This is an integer between 1 and 1048561 + * and MUST be in multiples of 16. */ + codec->width = atoi(value); + return 0; + } else if (!strcmp(attr, "height")) { + /* This is an integer between 1 and 1048561 + * and MUST be in multiples of 16. */ + codec->height = atoi(value); + return 0; + } else if (!strcmp(attr, "delivery-method")) { + /* Possible values are: inline, in_band, out_band/specific_name. */ + return AVERROR_PATCHWELCOME; + } else if (!strcmp(attr, "configuration-uri")) { + /* NOTE: configuration-uri is supported only under 2 conditions: + *--after the delivery-method tag + * --with a delivery-method value of out_band */ + return AVERROR_PATCHWELCOME; + } else if (!strcmp(attr, "configuration")) { + /* NOTE: configuration is supported only AFTER the delivery-method tag + * The configuration value is a base64 encoded packed header */ + uint8_t *decoded_packet = NULL; + int packet_size; + size_t decoded_alloc = strlen(value) / 4 * 3 + 4; + + if (decoded_alloc <= INT_MAX) { + decoded_packet = av_malloc(decoded_alloc); + if (decoded_packet) { + packet_size = + av_base64_decode(decoded_packet, value, decoded_alloc); + + result = parse_packed_headers + (decoded_packet, decoded_packet + packet_size, codec, + theora_data); + } else { + av_log(codec, AV_LOG_ERROR, + "Out of memory while decoding SDP configuration.\n"); + result = AVERROR_NOMEM; + } + } else { + av_log(codec, AV_LOG_ERROR, "Packet too large\n"); + result = AVERROR_INVALIDDATA; + } + av_free(decoded_packet); + } + return result; +} + +static int theora_parse_sdp_line(AVFormatContext *s, int st_index, + PayloadContext *data, const char *line) +{ + const char *p; + char *value; + char attr[25]; + int value_size = strlen(line), attr_size = sizeof(attr), res = 0; + AVCodecContext* codec = s->streams[st_index]->codec; + + assert(codec->id == CODEC_ID_THEORA); + assert(data); + + if (!(value = av_malloc(value_size))) { + av_log(codec, AV_LOG_ERROR, "Out of memory\n"); + return AVERROR_NOMEM; + } + + if (av_strstart(line, "fmtp:", &p)) { + // remove protocol identifier + while (*p && *p == ' ') p++; // strip spaces + while (*p && *p != ' ') p++; // eat protocol identifier + while (*p && *p == ' ') p++; // strip trailing spaces + + while (ff_rtsp_next_attr_and_value(&p, + attr, attr_size, + value, value_size)) { + res = theora_parse_fmtp_pair(codec, data, attr, value); + if (res < 0 && res != AVERROR_PATCHWELCOME) + return res; + } + } + + av_free(value); + return 0; +} + +RTPDynamicProtocolHandler ff_theora_dynamic_handler = { + .enc_name = "theora", + .codec_type = AVMEDIA_TYPE_VIDEO, + .codec_id = CODEC_ID_THEORA, + .parse_sdp_a_line = theora_parse_sdp_line, + .open = theora_new_context, + .close = theora_free_context, + .parse_packet = theora_handle_packet +}; diff -r 6cc73b15aa28 -r e3b4d7181606 rtpdec_xiph.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rtpdec_xiph.h Thu Apr 01 21:40:56 2010 +0000 @@ -0,0 +1,34 @@ +/* + * RTP Theora Protocol. + * Based off RFC 5215 (Vorbis RTP) and the Theora RTP draft. + * Copyright (c) 2010 Josh Allmann + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_RTPDEC_THEORA_H +#define AVFORMAT_RTPDEC_THEORA_H + +#include "libavcodec/avcodec.h" +#include "rtpdec.h" + +/** + * Theora RTP callbacks. + */ +extern RTPDynamicProtocolHandler ff_theora_dynamic_handler; + +#endif /* AVFORMAT_RTPDEC_THEORA_H */