~ubuntu-branches/ubuntu/trusty/libav/trusty-proposed

« back to all changes in this revision

Viewing changes to libavformat/rtpdec_vp8.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2013-10-22 23:24:08 UTC
  • mfrom: (1.3.36 sid)
  • Revision ID: package-import@ubuntu.com-20131022232408-b8tvvn4pyzri9mi3
Tags: 6:9.10-1ubuntu1
* Build all -extra flavors from this source package, as libav got demoted
  from main to universe, cf LP: #1243235
* Simplify debian/rules to follow exactly the code that debian executes
* New upstream (LP: #1180288) fixes lots of security issues (LP: #1242802)
* Merge from unstable, remaining changes:
  - build-depend on libtiff5-dev rather than libtiff4-dev,
    avoids FTBFS caused by imlib
  - follow the regular debian codepaths

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * RTP VP8 Depacketizer
3
3
 * Copyright (c) 2010 Josh Allmann
 
4
 * Copyright (c) 2012 Martin Storsjo
4
5
 *
5
6
 * This file is part of Libav.
6
7
 *
23
24
 * @file
24
25
 * @brief RTP support for the VP8 payload
25
26
 * @author Josh Allmann <joshua.allmann@gmail.com>
26
 
 * @see http://www.webmproject.org/code/specs/rtp/
 
27
 * @see http://tools.ietf.org/html/draft-ietf-payload-vp8-05
27
28
 */
28
29
 
29
30
#include "libavcodec/bytestream.h"
32
33
 
33
34
struct PayloadContext {
34
35
    AVIOContext *data;
35
 
    uint32_t       timestamp;
36
 
    int is_keyframe;
 
36
    uint32_t     timestamp;
 
37
    int          is_keyframe;
 
38
    int          sequence_ok;
 
39
    int          first_part_size;
 
40
    uint16_t     prev_seq;
 
41
    int          prev_pictureid;
 
42
    int          broken_frame;
37
43
};
38
44
 
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);
 
45
static void vp8_free_buffer(PayloadContext *vp8)
 
46
{
 
47
    uint8_t *tmp;
 
48
    if (!vp8->data)
 
49
        return;
 
50
    avio_close_dyn_buf(vp8->data, &tmp);
 
51
    av_free(tmp);
 
52
    vp8->data = NULL;
 
53
}
 
54
 
 
55
static int vp8_broken_sequence(AVFormatContext *ctx, PayloadContext *vp8,
 
56
                               const char *msg)
 
57
{
 
58
    vp8->sequence_ok = 0;
 
59
    av_log(ctx, AV_LOG_WARNING, "%s", msg);
 
60
    vp8_free_buffer(vp8);
 
61
    return AVERROR(EAGAIN);
 
62
}
 
63
 
 
64
static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8,
 
65
                             AVStream *st, AVPacket *pkt, uint32_t *timestamp,
 
66
                             const uint8_t *buf, int len, uint16_t seq,
 
67
                             int flags)
 
68
{
 
69
    int start_partition, end_packet;
 
70
    int extended_bits, part_id;
 
71
    int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0,
 
72
        keyidx_present = 0;
 
73
    int pictureid = -1, pictureid_mask;
 
74
    int returned_old_frame = 0;
 
75
    uint32_t old_timestamp;
58
76
 
59
77
    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;
 
78
        if (vp8->data) {
 
79
            int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
 
80
            if (ret < 0)
 
81
                return ret;
 
82
            return 0;
64
83
        }
65
 
        prepare_packet(pkt, vp8, st->index);
66
 
        *timestamp = vp8->timestamp;
67
 
        return 0;
 
84
        return AVERROR(EAGAIN);
68
85
    }
69
86
 
70
 
    start_packet = *buf & 1;
71
 
    end_packet   = flags & RTP_FLAG_MARKER;
72
 
    has_au       = *buf & 2;
 
87
    if (len < 1)
 
88
        return AVERROR_INVALIDDATA;
 
89
 
 
90
    extended_bits   = buf[0] & 0x80;
 
91
    start_partition = buf[0] & 0x10;
 
92
    part_id         = buf[0] & 0x0f;
 
93
    end_packet      = flags & RTP_FLAG_MARKER;
73
94
    buf++;
74
95
    len--;
 
96
    if (extended_bits) {
 
97
        if (len < 1)
 
98
            return AVERROR_INVALIDDATA;
 
99
        pictureid_present = buf[0] & 0x80;
 
100
        tl0picidx_present = buf[0] & 0x40;
 
101
        tid_present       = buf[0] & 0x20;
 
102
        keyidx_present    = buf[0] & 0x10;
 
103
        buf++;
 
104
        len--;
 
105
    }
 
106
    if (pictureid_present) {
 
107
        if (len < 1)
 
108
            return AVERROR_INVALIDDATA;
 
109
        if (buf[0] & 0x80) {
 
110
            if (len < 2)
 
111
                return AVERROR_INVALIDDATA;
 
112
            pictureid = AV_RB16(buf) & 0x7fff;
 
113
            pictureid_mask = 0x7fff;
 
114
            buf += 2;
 
115
            len -= 2;
 
116
        } else {
 
117
            pictureid = buf[0] & 0x7f;
 
118
            pictureid_mask = 0x7f;
 
119
            buf++;
 
120
            len--;
 
121
        }
 
122
    }
 
123
    if (tl0picidx_present) {
 
124
        // Ignoring temporal level zero index
 
125
        buf++;
 
126
        len--;
 
127
    }
 
128
    if (tid_present || keyidx_present) {
 
129
        // Ignoring temporal layer index, layer sync bit and keyframe index
 
130
        buf++;
 
131
        len--;
 
132
    }
 
133
    if (len < 1)
 
134
        return AVERROR_INVALIDDATA;
75
135
 
76
 
    if (start_packet) {
 
136
    if (start_partition && part_id == 0 && len >= 3) {
77
137
        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;
 
138
        int non_key = buf[0] & 0x01;
 
139
        if (!non_key) {
 
140
            vp8_free_buffer(vp8);
 
141
            // Keyframe, decoding ok again
 
142
            vp8->sequence_ok = 1;
 
143
        } else {
 
144
            int can_continue = vp8->data && !vp8->is_keyframe &&
 
145
                               avio_tell(vp8->data) >= vp8->first_part_size;
 
146
            if (!vp8->sequence_ok)
 
147
                return AVERROR(EAGAIN);
 
148
            if (pictureid >= 0) {
 
149
                if (pictureid != ((vp8->prev_pictureid + 1) & pictureid_mask)) {
 
150
                    return vp8_broken_sequence(ctx, vp8,
 
151
                                               "Missed a picture, sequence broken\n");
 
152
                } else {
 
153
                    if (vp8->data && !can_continue)
 
154
                        return vp8_broken_sequence(ctx, vp8,
 
155
                                                   "Missed a picture, sequence broken\n");
 
156
                }
 
157
            } else {
 
158
                uint16_t expected_seq = vp8->prev_seq + 1;
 
159
                int16_t diff = seq - expected_seq;
 
160
                if (vp8->data) {
 
161
                    // No picture id, so we can't know if missed packets
 
162
                    // contained any new frames. If diff == 0, we did get
 
163
                    // later packets from the same frame (matching timestamp),
 
164
                    // so we know we didn't miss any frame. If diff == 1 and
 
165
                    // we still have data (not flushed by the end of frame
 
166
                    // marker), the single missed packet must have been part
 
167
                    // of the same frame.
 
168
                    if ((diff == 0 || diff == 1) && can_continue) {
 
169
                        // Proceed with what we have
 
170
                    } else {
 
171
                        return vp8_broken_sequence(ctx, vp8,
 
172
                                                   "Missed too much, sequence broken\n");
 
173
                    }
 
174
                } else {
 
175
                    if (diff != 0)
 
176
                        return vp8_broken_sequence(ctx, vp8,
 
177
                                                   "Missed unknown data, sequence broken\n");
 
178
                }
 
179
            }
 
180
            if (vp8->data) {
 
181
                if (avio_tell(vp8->data) >= vp8->first_part_size) {
 
182
                    int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
 
183
                    if (ret < 0)
 
184
                        return ret;
 
185
                    pkt->size = vp8->first_part_size;
 
186
                    returned_old_frame = 1;
 
187
                    old_timestamp = vp8->timestamp;
 
188
                } else {
 
189
                    // Shouldn't happen
 
190
                    vp8_free_buffer(vp8);
 
191
                }
 
192
            }
87
193
        }
 
194
        vp8->first_part_size = (AV_RL16(&buf[1]) << 3 | buf[0] >> 5) + 3;
88
195
        if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
89
196
            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;
 
197
        vp8->timestamp = *timestamp;
 
198
        vp8->broken_frame = 0;
 
199
        vp8->prev_pictureid = pictureid;
 
200
        vp8->is_keyframe = !non_key;
 
201
    } else {
 
202
        uint16_t expected_seq = vp8->prev_seq + 1;
 
203
 
 
204
        if (!vp8->sequence_ok)
 
205
            return AVERROR(EAGAIN);
 
206
 
 
207
        if (vp8->timestamp != *timestamp) {
 
208
            // Missed the start of the new frame, sequence broken
 
209
            vp8->sequence_ok = 0;
 
210
            av_log(ctx, AV_LOG_WARNING,
 
211
                   "Received no start marker; dropping frame\n");
 
212
            vp8_free_buffer(vp8);
 
213
            return AVERROR(EAGAIN);
 
214
        }
 
215
 
 
216
        if (seq != expected_seq) {
 
217
            if (vp8->is_keyframe) {
 
218
                return vp8_broken_sequence(ctx, vp8,
 
219
                                           "Missed part of a keyframe, sequence broken\n");
 
220
            } else if (vp8->data && avio_tell(vp8->data) >= vp8->first_part_size) {
 
221
                vp8->broken_frame = 1;
 
222
            } else {
 
223
                return vp8_broken_sequence(ctx, vp8,
 
224
                                           "Missed part of the first partition, sequence broken\n");
111
225
            }
112
226
        }
113
 
 
114
 
        avio_write(vp8->data, buf, au_len);
115
 
        buf += au_len;
116
 
        len -= au_len;
117
227
    }
118
228
 
119
 
    if (ret != AVERROR(EAGAIN)) // did we miss a end marker?
120
 
        return ret;
 
229
    if (!vp8->data)
 
230
        return vp8_broken_sequence(ctx, vp8, "Received no start marker\n");
 
231
 
 
232
    vp8->prev_seq = seq;
 
233
    avio_write(vp8->data, buf, len);
121
234
 
122
235
    if (end_packet) {
123
 
        prepare_packet(pkt, vp8, st->index);
 
236
        int ret;
 
237
        if (returned_old_frame) {
 
238
            *timestamp = old_timestamp;
 
239
            return 1;
 
240
        }
 
241
        ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
 
242
        if (ret < 0)
 
243
            return ret;
 
244
        if (vp8->broken_frame)
 
245
            pkt->size = vp8->first_part_size;
124
246
        return 0;
125
247
    }
126
248
 
129
251
 
130
252
static PayloadContext *vp8_new_context(void)
131
253
{
132
 
    av_log(NULL, AV_LOG_ERROR, "RTP VP8 payload implementation is incompatible "
133
 
                               "with the latest spec drafts.\n");
134
254
    return av_mallocz(sizeof(PayloadContext));
135
255
}
136
256
 
137
257
static void vp8_free_context(PayloadContext *vp8)
138
258
{
139
 
    if (vp8->data) {
140
 
        uint8_t *tmp;
141
 
        avio_close_dyn_buf(vp8->data, &tmp);
142
 
        av_free(tmp);
143
 
    }
 
259
    vp8_free_buffer(vp8);
144
260
    av_free(vp8);
145
261
}
146
262
 
147
263
RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
148
264
    .enc_name       = "VP8",
149
265
    .codec_type     = AVMEDIA_TYPE_VIDEO,
150
 
    .codec_id       = CODEC_ID_VP8,
 
266
    .codec_id       = AV_CODEC_ID_VP8,
151
267
    .alloc          = vp8_new_context,
152
268
    .free           = vp8_free_context,
153
269
    .parse_packet   = vp8_handle_packet,