| Index: source/patched-ffmpeg-mt/libavformat/rtpdec_vp8.c
|
| ===================================================================
|
| --- source/patched-ffmpeg-mt/libavformat/rtpdec_vp8.c (revision 0)
|
| +++ source/patched-ffmpeg-mt/libavformat/rtpdec_vp8.c (revision 0)
|
| @@ -0,0 +1,153 @@
|
| +/*
|
| + * 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,
|
| +};
|
|
|