Statistics
| Branch: | Revision:

ffmpeg / libavformat / rtpdec_vp8.c @ 9261e6cf

History | View | Annotate | Download (4.51 KB)

1
/*
2
 * RTP VP8 Depacketizer
3
 * Copyright (c) 2010 Josh Allmann
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * Libav is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

    
22
/**
23
 * @file
24
 * @brief RTP support for the VP8 payload
25
 * @author Josh Allmann <joshua.allmann@gmail.com>
26
 * ( http://www.webmproject.org/code/specs/rtp/ )
27
 */
28

    
29
#include "libavcodec/bytestream.h"
30

    
31
#include "rtpdec_formats.h"
32

    
33
struct PayloadContext {
34
    AVIOContext *data;
35
    uint32_t       timestamp;
36
    int is_keyframe;
37
};
38

    
39
static void prepare_packet(AVPacket *pkt, PayloadContext *vp8, int stream)
40
{
41
    av_init_packet(pkt);
42
    pkt->stream_index = stream;
43
    pkt->flags        = vp8->is_keyframe ? AV_PKT_FLAG_KEY : 0;
44
    pkt->size         = avio_close_dyn_buf(vp8->data, &pkt->data);
45
    pkt->destruct     = av_destruct_packet;
46
    vp8->data         = NULL;
47
}
48

    
49
static int vp8_handle_packet(AVFormatContext *ctx,
50
                             PayloadContext *vp8,
51
                             AVStream *st,
52
                             AVPacket *pkt,
53
                             uint32_t *timestamp,
54
                             const uint8_t *buf,
55
                             int len, int flags)
56
{
57
    int start_packet, end_packet, has_au, ret = AVERROR(EAGAIN);
58

    
59
    if (!buf) {
60
        // only called when vp8_handle_packet returns 1
61
        if (!vp8->data) {
62
            av_log(ctx, AV_LOG_ERROR, "Invalid VP8 data passed\n");
63
            return AVERROR_INVALIDDATA;
64
        }
65
        prepare_packet(pkt, vp8, st->index);
66
        *timestamp = vp8->timestamp;
67
        return 0;
68
    }
69

    
70
    start_packet = *buf & 1;
71
    end_packet   = flags & RTP_FLAG_MARKER;
72
    has_au       = *buf & 2;
73
    buf++;
74
    len--;
75

    
76
    if (start_packet) {
77
        int res;
78
        uint32_t ts = *timestamp;
79
        if (vp8->data) {
80
            // missing end marker; return old frame anyway. untested
81
            prepare_packet(pkt, vp8, st->index);
82
            *timestamp = vp8->timestamp; // reset timestamp from old frame
83

    
84
            // if current frame fits into one rtp packet, need to hold
85
            // that for the next av_get_packet call
86
            ret = end_packet ? 1 : 0;
87
        }
88
        if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
89
            return res;
90
        vp8->is_keyframe = *buf & 1;
91
        vp8->timestamp   = ts;
92
     }
93

    
94
    if (!vp8->data || vp8->timestamp != *timestamp && ret == AVERROR(EAGAIN)) {
95
        av_log(ctx, AV_LOG_WARNING,
96
               "Received no start marker; dropping frame\n");
97
        return AVERROR(EAGAIN);
98
    }
99

    
100
    // cycle through VP8AU headers if needed
101
    // not tested with actual VP8AUs
102
    while (len) {
103
        int au_len = len;
104
        if (has_au && len > 2) {
105
            au_len = AV_RB16(buf);
106
            buf += 2;
107
            len -= 2;
108
            if (buf + au_len > buf + len) {
109
                av_log(ctx, AV_LOG_ERROR, "Invalid VP8AU length\n");
110
                return AVERROR_INVALIDDATA;
111
            }
112
        }
113

    
114
        avio_write(vp8->data, buf, au_len);
115
        buf += au_len;
116
        len -= au_len;
117
    }
118

    
119
    if (ret != AVERROR(EAGAIN)) // did we miss a end marker?
120
        return ret;
121

    
122
    if (end_packet) {
123
        prepare_packet(pkt, vp8, st->index);
124
        return 0;
125
    }
126

    
127
    return AVERROR(EAGAIN);
128
}
129

    
130
static PayloadContext *vp8_new_context(void)
131
{
132
    av_log(NULL, AV_LOG_ERROR, "RTP VP8 payload implementation is incompatible "
133
                               "with the latest spec drafts.\n");
134
    return av_mallocz(sizeof(PayloadContext));
135
}
136

    
137
static void vp8_free_context(PayloadContext *vp8)
138
{
139
    if (vp8->data) {
140
        uint8_t *tmp;
141
        avio_close_dyn_buf(vp8->data, &tmp);
142
        av_free(tmp);
143
    }
144
    av_free(vp8);
145
}
146

    
147
RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
148
    .enc_name       = "VP8",
149
    .codec_type     = AVMEDIA_TYPE_VIDEO,
150
    .codec_id       = CODEC_ID_VP8,
151
    .alloc          = vp8_new_context,
152
    .free           = vp8_free_context,
153
    .parse_packet   = vp8_handle_packet,
154
};