99ca60a6f7c496c592af074ffde4d2dc5b72b630
[ffmpeg.git] / libavformat / rtpdec_vp8.c
1 /*
2  * RTP VP8 Depacketizer
3  * Copyright (c) 2010 Josh Allmann
4  * Copyright (c) 2012 Martin Storsjo
5  *
6  * This file is part of Libav.
7  *
8  * Libav is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * Libav is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with Libav; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22
23 /**
24  * @file
25  * @brief RTP support for the VP8 payload
26  * @author Josh Allmann <joshua.allmann@gmail.com>
27  * @see http://tools.ietf.org/html/draft-ietf-payload-vp8-05
28  */
29
30 #include "libavcodec/bytestream.h"
31
32 #include "rtpdec_formats.h"
33
34 struct PayloadContext {
35     AVIOContext *data;
36     uint32_t     timestamp;
37 };
38
39 static int vp8_handle_packet(AVFormatContext *ctx,
40                              PayloadContext *vp8,
41                              AVStream *st,
42                              AVPacket *pkt,
43                              uint32_t *timestamp,
44                              const uint8_t *buf,
45                              int len, int flags)
46 {
47     int start_partition, end_packet;
48     int extended_bits, part_id;
49     int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0,
50         keyidx_present = 0;
51
52     if (len < 1)
53         return AVERROR_INVALIDDATA;
54
55     extended_bits   = buf[0] & 0x80;
56     start_partition = buf[0] & 0x10;
57     part_id         = buf[0] & 0x0f;
58     end_packet      = flags & RTP_FLAG_MARKER;
59     buf++;
60     len--;
61     if (extended_bits) {
62         if (len < 1)
63             return AVERROR_INVALIDDATA;
64         pictureid_present = buf[0] & 0x80;
65         tl0picidx_present = buf[0] & 0x40;
66         tid_present       = buf[0] & 0x20;
67         keyidx_present    = buf[0] & 0x10;
68         buf++;
69         len--;
70     }
71     if (pictureid_present) {
72         int size;
73         if (len < 1)
74             return AVERROR_INVALIDDATA;
75         size = buf[0] & 0x80 ? 2 : 1;
76         buf += size;
77         len -= size;
78     }
79     if (tl0picidx_present) {
80         // Ignoring temporal level zero index
81         buf++;
82         len--;
83     }
84     if (tid_present || keyidx_present) {
85         // Ignoring temporal layer index, layer sync bit and keyframe index
86         buf++;
87         len--;
88     }
89     if (len < 1)
90         return AVERROR_INVALIDDATA;
91
92     if (start_partition && part_id == 0) {
93         int res;
94         if (vp8->data) {
95             uint8_t *tmp;
96             avio_close_dyn_buf(vp8->data, &tmp);
97             av_free(tmp);
98             vp8->data = NULL;
99         }
100         if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
101             return res;
102         vp8->timestamp = *timestamp;
103     }
104
105     if (!vp8->data || vp8->timestamp != *timestamp) {
106         av_log(ctx, AV_LOG_WARNING,
107                "Received no start marker; dropping frame\n");
108         return AVERROR(EAGAIN);
109     }
110
111     avio_write(vp8->data, buf, len);
112
113     if (end_packet) {
114         int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
115         if (ret < 0)
116             return ret;
117         return 0;
118     }
119
120     return AVERROR(EAGAIN);
121 }
122
123 static PayloadContext *vp8_new_context(void)
124 {
125     return av_mallocz(sizeof(PayloadContext));
126 }
127
128 static void vp8_free_context(PayloadContext *vp8)
129 {
130     if (vp8->data) {
131         uint8_t *tmp;
132         avio_close_dyn_buf(vp8->data, &tmp);
133         av_free(tmp);
134     }
135     av_free(vp8);
136 }
137
138 RTPDynamicProtocolHandler ff_vp8_dynamic_handler = {
139     .enc_name       = "VP8",
140     .codec_type     = AVMEDIA_TYPE_VIDEO,
141     .codec_id       = AV_CODEC_ID_VP8,
142     .alloc          = vp8_new_context,
143     .free           = vp8_free_context,
144     .parse_packet   = vp8_handle_packet,
145 };