Patch by Josh Allmann, joshua dot allmann at gmail Originally committed as revision 24735 to svn://svn.ffmpeg.org/ffmpeg/trunktags/n0.8
| @@ -27,6 +27,7 @@ version <next>: | |||
| - SubRip subtitle file muxer and demuxer | |||
| - Chinese AVS encoding via libxavs | |||
| - ffprobe -show_packets option added | |||
| - RTP packetization of Theora and Vorbis | |||
| @@ -219,6 +219,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ | |||
| rtpenc_mpv.o \ | |||
| rtpenc.o \ | |||
| rtpenc_h264.o \ | |||
| rtpenc_xiph.o \ | |||
| avc.o | |||
| OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o httpauth.o | |||
| OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o | |||
| @@ -23,7 +23,7 @@ | |||
| #define LIBAVFORMAT_VERSION_MAJOR 52 | |||
| #define LIBAVFORMAT_VERSION_MINOR 78 | |||
| #define LIBAVFORMAT_VERSION_MICRO 0 | |||
| #define LIBAVFORMAT_VERSION_MICRO 1 | |||
| #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ | |||
| LIBAVFORMAT_VERSION_MINOR, \ | |||
| @@ -53,6 +53,8 @@ static int is_supported(enum CodecID id) | |||
| case CODEC_ID_MPEG2TS: | |||
| case CODEC_ID_AMR_NB: | |||
| case CODEC_ID_AMR_WB: | |||
| case CODEC_ID_VORBIS: | |||
| case CODEC_ID_THEORA: | |||
| return 1; | |||
| default: | |||
| return 0; | |||
| @@ -135,6 +137,13 @@ static int rtp_write_header(AVFormatContext *s1) | |||
| s->nal_length_size = (st->codec->extradata[4] & 0x03) + 1; | |||
| } | |||
| break; | |||
| case CODEC_ID_VORBIS: | |||
| case CODEC_ID_THEORA: | |||
| if (!s->max_frames_per_packet) s->max_frames_per_packet = 15; | |||
| s->max_frames_per_packet = av_clip(s->max_frames_per_packet, 1, 15); | |||
| s->max_payload_size -= 6; // ident+frag+tdt/vdt+pkt_num+pkt_length | |||
| s->num_frames = 0; | |||
| goto defaultcase; | |||
| case CODEC_ID_AMR_NB: | |||
| case CODEC_ID_AMR_WB: | |||
| if (!s->max_frames_per_packet) | |||
| @@ -155,6 +164,7 @@ static int rtp_write_header(AVFormatContext *s1) | |||
| case CODEC_ID_AAC: | |||
| s->num_frames = 0; | |||
| default: | |||
| defaultcase: | |||
| if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { | |||
| av_set_pts_info(st, 32, 1, st->codec->sample_rate); | |||
| } | |||
| @@ -393,6 +403,10 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) | |||
| case CODEC_ID_H263P: | |||
| ff_rtp_send_h263(s1, pkt->data, size); | |||
| break; | |||
| case CODEC_ID_VORBIS: | |||
| case CODEC_ID_THEORA: | |||
| ff_rtp_send_xiph(s1, pkt->data, size); | |||
| break; | |||
| default: | |||
| /* better than nothing : send the codec raw data */ | |||
| rtp_send_raw(s1, pkt->data, size); | |||
| @@ -67,5 +67,6 @@ void ff_rtp_send_h263(AVFormatContext *s1, const uint8_t *buf1, int size); | |||
| void ff_rtp_send_aac(AVFormatContext *s1, const uint8_t *buff, int size); | |||
| void ff_rtp_send_amr(AVFormatContext *s1, const uint8_t *buff, int size); | |||
| void ff_rtp_send_mpegvideo(AVFormatContext *s1, const uint8_t *buf1, int size); | |||
| void ff_rtp_send_xiph(AVFormatContext *s1, const uint8_t *buff, int size); | |||
| #endif /* AVFORMAT_RTPENC_H */ | |||
| @@ -0,0 +1,125 @@ | |||
| /* | |||
| * RTP packetization for Xiph audio and video | |||
| * 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 | |||
| */ | |||
| #include "avformat.h" | |||
| #include "rtpenc.h" | |||
| /** | |||
| * Packetize Xiph frames into RTP according to | |||
| * RFC 5215 (Vorbis) and the Theora RFC draft. | |||
| * (http://svn.xiph.org/trunk/theora/doc/draft-ietf-avt-rtp-theora-00.txt) | |||
| */ | |||
| void ff_rtp_send_xiph(AVFormatContext *s1, const uint8_t *buff, int size) | |||
| { | |||
| RTPMuxContext *s = s1->priv_data; | |||
| int max_pkt_size, xdt, frag; | |||
| uint8_t *q; | |||
| max_pkt_size = s->max_payload_size; | |||
| // set xiph data type | |||
| switch (*buff) { | |||
| case 0x01: // vorbis id | |||
| case 0x05: // vorbis setup | |||
| case 0x80: // theora header | |||
| case 0x82: // theora tables | |||
| xdt = 1; // packed config payload | |||
| break; | |||
| case 0x03: // vorbis comments | |||
| case 0x81: // theora comments | |||
| xdt = 2; // comment payload | |||
| break; | |||
| default: | |||
| xdt = 0; // raw data payload | |||
| break; | |||
| } | |||
| // Set ident. Must match the one in sdp.c | |||
| // Probably need a non-fixed way of generating | |||
| // this, but it has to be done in SDP and passed in from there. | |||
| q = s->buf; | |||
| *q++ = 0xfe; | |||
| *q++ = 0xcd; | |||
| *q++ = 0xba; | |||
| // set fragment | |||
| // 0 - whole frame (possibly multiple frames) | |||
| // 1 - first fragment | |||
| // 2 - fragment continuation | |||
| // 3 - last fragmement | |||
| frag = size <= max_pkt_size ? 0 : 1; | |||
| if (!frag && !xdt) { // do we have a whole frame of raw data? | |||
| unsigned end_ptr = (unsigned)s->buf + 6 + max_pkt_size; // what we're allowed to write | |||
| unsigned ptr = (unsigned)s->buf_ptr + 2 + size; // what we're going to write | |||
| int remaining = end_ptr - ptr; | |||
| if ((s->num_frames > 0 && remaining < 0) || | |||
| s->num_frames >= s->max_frames_per_packet) { | |||
| // send previous packets now; no room for new data | |||
| ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0); | |||
| s->num_frames = 0; | |||
| } | |||
| // buffer current frame to send later | |||
| if (0 == s->num_frames) s->timestamp = s->cur_timestamp; | |||
| s->num_frames++; | |||
| // Set packet header. Normally, this is OR'd with frag and xdt, | |||
| // but those are zero, so omitted here | |||
| *q++ = s->num_frames; | |||
| if (s->num_frames > 1) q = s->buf_ptr; // jump ahead if needed | |||
| *q++ = (size >> 8) & 0xff; | |||
| *q++ = size & 0xff; | |||
| memcpy(q, buff, size); | |||
| q += size; | |||
| s->buf_ptr = q; | |||
| return; | |||
| } else if (s->num_frames) { | |||
| // immediately send buffered frames if buffer is not raw data, | |||
| // or if current frame is fragmented. | |||
| ff_rtp_send_data(s1, s->buf, s->buf_ptr - s->buf, 0); | |||
| } | |||
| s->timestamp = s->cur_timestamp; | |||
| s->num_frames = 0; | |||
| s->buf_ptr = q; | |||
| while (size > 0) { | |||
| int len = (!frag || frag == 3) ? size : max_pkt_size; | |||
| q = s->buf_ptr; | |||
| // set packet headers | |||
| *q++ = (frag << 6) | (xdt << 4); // num_frames = 0 | |||
| *q++ = (len >> 8) & 0xff; | |||
| *q++ = len & 0xff; | |||
| // set packet body | |||
| memcpy(q, buff, len); | |||
| q += len; | |||
| buff += len; | |||
| size -= len; | |||
| ff_rtp_send_data(s1, s->buf, q - s->buf, 0); | |||
| frag = size <= max_pkt_size ? 3 : 2; | |||
| } | |||
| } | |||
| @@ -52,7 +52,7 @@ int rtsp_default_protocols = (1 << RTSP_LOWER_TRANSPORT_UDP); | |||
| #define SELECT_TIMEOUT_MS 100 | |||
| #define READ_PACKET_TIMEOUT_S 10 | |||
| #define MAX_TIMEOUTS READ_PACKET_TIMEOUT_S * 1000 / SELECT_TIMEOUT_MS | |||
| #define SDP_MAX_SIZE 8192 | |||
| #define SDP_MAX_SIZE 16384 | |||
| static void get_word_until_chars(char *buf, int buf_size, | |||
| const char *sep, const char **pp) | |||
| @@ -21,6 +21,7 @@ | |||
| #include <string.h> | |||
| #include "libavutil/avstring.h" | |||
| #include "libavutil/base64.h" | |||
| #include "libavcodec/xiph.h" | |||
| #include "avformat.h" | |||
| #include "internal.h" | |||
| #include "avc.h" | |||
| @@ -220,6 +221,75 @@ static char *extradata2config(AVCodecContext *c) | |||
| return config; | |||
| } | |||
| static char *xiph_extradata2config(AVCodecContext *c) | |||
| { | |||
| char *config, *encoded_config; | |||
| uint8_t *header_start[3]; | |||
| int headers_len, header_len[3], config_len; | |||
| int first_header_size; | |||
| switch (c->codec_id) { | |||
| case CODEC_ID_THEORA: | |||
| first_header_size = 42; | |||
| break; | |||
| case CODEC_ID_VORBIS: | |||
| first_header_size = 30; | |||
| break; | |||
| default: | |||
| av_log(c, AV_LOG_ERROR, "Unsupported Xiph codec ID\n"); | |||
| return NULL; | |||
| } | |||
| if (ff_split_xiph_headers(c->extradata, c->extradata_size, | |||
| first_header_size, header_start, | |||
| header_len) < 0) { | |||
| av_log(c, AV_LOG_ERROR, "Extradata corrupt.\n"); | |||
| return NULL; | |||
| } | |||
| headers_len = header_len[0] + header_len[2]; | |||
| config_len = 4 + // count | |||
| 3 + // ident | |||
| 2 + // packet size | |||
| 1 + // header count | |||
| 2 + // header size | |||
| headers_len; // and the rest | |||
| config = av_malloc(config_len); | |||
| if (!config) | |||
| goto xiph_fail; | |||
| encoded_config = av_malloc(AV_BASE64_SIZE(config_len)); | |||
| if (!encoded_config) { | |||
| av_free(config); | |||
| goto xiph_fail; | |||
| } | |||
| config[0] = config[1] = config[2] = 0; | |||
| config[3] = 1; | |||
| config[4] = 0xfe; // ident must match the one in rtpenc_xiph.c | |||
| config[5] = 0xcd; | |||
| config[6] = 0xba; | |||
| config[7] = (headers_len >> 8) & 0xff; | |||
| config[8] = headers_len & 0xff; | |||
| config[9] = 2; | |||
| config[10] = header_len[0]; | |||
| config[11] = 0; // size of comment header; nonexistent | |||
| memcpy(config + 12, header_start[0], header_len[0]); | |||
| memcpy(config + 12 + header_len[0], header_start[2], header_len[2]); | |||
| av_base64_encode(encoded_config, AV_BASE64_SIZE(config_len), | |||
| config, config_len); | |||
| av_free(config); | |||
| return encoded_config; | |||
| xiph_fail: | |||
| av_log(c, AV_LOG_ERROR, | |||
| "Not enough memory for configuration string\n"); | |||
| return NULL; | |||
| } | |||
| static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, int payload_type) | |||
| { | |||
| char *config = NULL; | |||
| @@ -297,6 +367,51 @@ static char *sdp_write_media_attributes(char *buff, int size, AVCodecContext *c, | |||
| payload_type, c->sample_rate, c->channels, | |||
| payload_type); | |||
| break; | |||
| case CODEC_ID_VORBIS: | |||
| if (c->extradata_size) | |||
| config = xiph_extradata2config(c); | |||
| else | |||
| av_log(c, AV_LOG_ERROR, "Vorbis configuration info missing\n"); | |||
| if (!config) | |||
| return NULL; | |||
| av_strlcatf(buff, size, "a=rtpmap:%d vorbis/%d/%d\r\n" | |||
| "a=fmtp:%d configuration=%s\r\n", | |||
| payload_type, c->sample_rate, c->channels, | |||
| payload_type, config); | |||
| break; | |||
| case CODEC_ID_THEORA: { | |||
| const char *pix_fmt; | |||
| if (c->extradata_size) | |||
| config = xiph_extradata2config(c); | |||
| else | |||
| av_log(c, AV_LOG_ERROR, "Theora configuation info missing\n"); | |||
| if (!config) | |||
| return NULL; | |||
| switch (c->pix_fmt) { | |||
| case PIX_FMT_YUV420P: | |||
| pix_fmt = "YCbCr-4:2:0"; | |||
| break; | |||
| case PIX_FMT_YUV422P: | |||
| pix_fmt = "YCbCr-4:2:2"; | |||
| break; | |||
| case PIX_FMT_YUV444P: | |||
| pix_fmt = "YCbCr-4:4:4"; | |||
| break; | |||
| default: | |||
| av_log(c, AV_LOG_ERROR, "Unsupported pixel format.\n"); | |||
| return NULL; | |||
| } | |||
| av_strlcatf(buff, size, "a=rtpmap:%d theora/90000\r\n" | |||
| "a=fmtp:%d delivery-method=inline; " | |||
| "width=%d; height=%d; sampling=%s; " | |||
| "configuration=%s\r\n", | |||
| payload_type, payload_type, | |||
| c->width, c->height, pix_fmt, config); | |||
| break; | |||
| } | |||
| default: | |||
| /* Nothing special to do here... */ | |||
| break; | |||