FFmpeg/libavformat/rtpdec_vp8.c
Michael Niedermayer 7a72695c05 Merge commit '36ef5369ee9b336febc2c270f8718cec4476cb85'
* commit '36ef5369ee9b336febc2c270f8718cec4476cb85':
  Replace all CODEC_ID_* with AV_CODEC_ID_*
  lavc: add AV prefix to codec ids.

Conflicts:
	doc/APIchanges
	doc/examples/decoding_encoding.c
	doc/examples/muxing.c
	ffmpeg.c
	ffprobe.c
	ffserver.c
	libavcodec/8svx.c
	libavcodec/avcodec.h
	libavcodec/dnxhd_parser.c
	libavcodec/dvdsubdec.c
	libavcodec/error_resilience.c
	libavcodec/h263dec.c
	libavcodec/libvorbisenc.c
	libavcodec/mjpeg_parser.c
	libavcodec/mjpegenc.c
	libavcodec/mpeg12.c
	libavcodec/mpeg4videodec.c
	libavcodec/mpegvideo.c
	libavcodec/mpegvideo_enc.c
	libavcodec/pcm.c
	libavcodec/r210dec.c
	libavcodec/utils.c
	libavcodec/v210dec.c
	libavcodec/version.h
	libavdevice/alsa-audio-dec.c
	libavdevice/bktr.c
	libavdevice/v4l2.c
	libavformat/asfdec.c
	libavformat/asfenc.c
	libavformat/avformat.h
	libavformat/avidec.c
	libavformat/caf.c
	libavformat/electronicarts.c
	libavformat/flacdec.c
	libavformat/flvdec.c
	libavformat/flvenc.c
	libavformat/framecrcenc.c
	libavformat/img2.c
	libavformat/img2dec.c
	libavformat/img2enc.c
	libavformat/ipmovie.c
	libavformat/isom.c
	libavformat/matroska.c
	libavformat/matroskadec.c
	libavformat/matroskaenc.c
	libavformat/mov.c
	libavformat/movenc.c
	libavformat/mp3dec.c
	libavformat/mpeg.c
	libavformat/mpegts.c
	libavformat/mxf.c
	libavformat/mxfdec.c
	libavformat/mxfenc.c
	libavformat/nsvdec.c
	libavformat/nut.c
	libavformat/oggenc.c
	libavformat/pmpdec.c
	libavformat/rawdec.c
	libavformat/rawenc.c
	libavformat/riff.c
	libavformat/sdp.c
	libavformat/utils.c
	libavformat/vocenc.c
	libavformat/wtv.c
	libavformat/xmv.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
2012-08-07 22:45:46 +02:00

155 lines
4.5 KiB
C

/*
* 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>
* @see http://www.webmproject.org/code/specs/rtp/
*/
#include "libavcodec/bytestream.h"
#include "rtpdec_formats.h"
struct PayloadContext {
AVIOContext *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 = avio_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 = avio_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;
}
}
avio_write(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_ERROR, "RTP VP8 payload implementation is incompatible "
"with the latest spec drafts.\n");
return av_mallocz(sizeof(PayloadContext));
}
static void vp8_free_context(PayloadContext *vp8)
{
if (vp8->data) {
uint8_t *tmp;
avio_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 = AV_CODEC_ID_VP8,
.alloc = vp8_new_context,
.free = vp8_free_context,
.parse_packet = vp8_handle_packet,
};