Commit 51291e60 authored by Josh Allmann's avatar Josh Allmann Committed by Martin Storsjö

Add RTP depacketization of VP8

Patch by Josh Allmann, joshua dot allmann at gmail

Originally committed as revision 24798 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 7b18d94c
......@@ -29,6 +29,7 @@ version <next>:
- ffprobe -show_packets option added
- RTP packetization of Theora and Vorbis
- RTP depacketization of MP4A-LATM
- RTP packetization and depacketization of VP8
version 0.6:
......
......@@ -236,6 +236,7 @@ OBJS-$(CONFIG_SDP_DEMUXER) += rtsp.o \
rtpdec_mpeg4.o \
rtpdec_qdm2.o \
rtpdec_svq3.o \
rtpdec_vp8.o \
rtpdec_xiph.o
OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o
OBJS-$(CONFIG_SHORTEN_DEMUXER) += raw.o
......
......@@ -23,7 +23,7 @@
#define LIBAVFORMAT_VERSION_MAJOR 52
#define LIBAVFORMAT_VERSION_MINOR 78
#define LIBAVFORMAT_VERSION_MICRO 2
#define LIBAVFORMAT_VERSION_MICRO 3
#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
LIBAVFORMAT_VERSION_MINOR, \
......
......@@ -66,6 +66,7 @@ void av_register_rtp_dynamic_payload_handlers(void)
ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler);
ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler);
ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler);
......
......@@ -45,5 +45,6 @@ extern RTPDynamicProtocolHandler ff_qdm2_dynamic_handler;
extern RTPDynamicProtocolHandler ff_svq3_dynamic_handler;
extern RTPDynamicProtocolHandler ff_theora_dynamic_handler;
extern RTPDynamicProtocolHandler ff_vorbis_dynamic_handler;
extern RTPDynamicProtocolHandler ff_vp8_dynamic_handler;
#endif /* AVFORMAT_RTPDEC_FORMATS_H */
/*
* RTP VP8 Depacketizer
* 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
* @brief RTP support for the VP8 payload
* @author Josh Allmann <joshua.allmann@gmail.com>
* ( http://www.webmproject.org/code/specs/rtp/ )
*/
#include "libavcodec/bytestream.h"
#include "rtpdec_formats.h"
struct PayloadContext {
ByteIOContext *data;
uint32_t timestamp;
int is_keyframe;
};
static void prepare_packet(AVPacket *pkt, PayloadContext *vp8, int stream)
{
av_init_packet(pkt);
pkt->stream_index = stream;
pkt->flags = vp8->is_keyframe ? AV_PKT_FLAG_KEY : 0;
pkt->size = url_close_dyn_buf(vp8->data, &pkt->data);
pkt->destruct = av_destruct_packet;
vp8->data = NULL;
}
static int vp8_handle_packet(AVFormatContext *ctx,
PayloadContext *vp8,
AVStream *st,
AVPacket *pkt,
uint32_t *timestamp,
const uint8_t *buf,
int len, int flags)
{
int start_packet, end_packet, has_au, ret = AVERROR(EAGAIN);
if (!buf) {
// only called when vp8_handle_packet returns 1
if (!vp8->data) {
av_log(ctx, AV_LOG_ERROR, "Invalid VP8 data passed\n");
return AVERROR_INVALIDDATA;
}
prepare_packet(pkt, vp8, st->index);
*timestamp = vp8->timestamp;
return 0;
}
start_packet = *buf & 1;
end_packet = flags & RTP_FLAG_MARKER;
has_au = *buf & 2;
buf++;
len--;
if (start_packet) {
int res;
uint32_t ts = *timestamp;
if (vp8->data) {
// missing end marker; return old frame anyway. untested
prepare_packet(pkt, vp8, st->index);
*timestamp = vp8->timestamp; // reset timestamp from old frame
// if current frame fits into one rtp packet, need to hold
// that for the next av_get_packet call
ret = end_packet ? 1 : 0;
}
if ((res = url_open_dyn_buf(&vp8->data)) < 0)
return res;
vp8->is_keyframe = *buf & 1;
vp8->timestamp = ts;
}
if (!vp8->data || vp8->timestamp != *timestamp && ret == AVERROR(EAGAIN)) {
av_log(ctx, AV_LOG_WARNING,
"Received no start marker; dropping frame\n");
return AVERROR(EAGAIN);
}
// cycle through VP8AU headers if needed
// not tested with actual VP8AUs
while (len) {
int au_len = len;
if (has_au && len > 2) {
au_len = AV_RB16(buf);
buf += 2;
len -= 2;
if (buf + au_len > buf + len) {
av_log(ctx, AV_LOG_ERROR, "Invalid VP8AU length\n");
return AVERROR_INVALIDDATA;
}
}
put_buffer(vp8->data, buf, au_len);
buf += au_len;
len -= au_len;
}
if (ret != AVERROR(EAGAIN)) // did we miss a end marker?
return ret;
if (end_packet) {
prepare_packet(pkt, vp8, st->index);
return 0;
}
return AVERROR(EAGAIN);
}
static PayloadContext *vp8_new_context(void)
{
av_log(NULL, AV_LOG_WARNING, "RTP VP8 payload is still experimental\n");
return av_mallocz(sizeof(PayloadContext));
}
static void vp8_free_context(PayloadContext *vp8)
{
if (vp8->data) {
uint8_t *tmp;
url_close_dyn_buf(vp8->data, &tmp);
av_free(tmp);
}
av_free(vp8);
}
RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
.enc_name = "VP8",
.codec_type = AVMEDIA_TYPE_VIDEO,
.codec_id = CODEC_ID_VP8,
.open = vp8_new_context,
.close = vp8_free_context,
.parse_packet = vp8_handle_packet,
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment