FFmpeg
rtpdec_vp8.c
Go to the documentation of this file.
1 /*
2  * RTP VP8 Depacketizer
3  * Copyright (c) 2010 Josh Allmann
4  * Copyright (c) 2012 Martin Storsjo
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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 "avio_internal.h"
33 #include "rtpdec_formats.h"
34 
35 struct PayloadContext {
37  uint32_t timestamp;
39  /* If sequence_ok is set, we keep returning data (even if we might have
40  * lost some data, but we haven't lost any too critical data that would
41  * cause the decoder to desynchronize and output random garbage).
42  */
45  uint16_t prev_seq;
48  /* If sequence_dirty is set, we have lost some data (critical or
49  * non-critical) and decoding will have some sort of artifacts, and
50  * we thus should request a new keyframe.
51  */
54 };
55 
57  const char *msg)
58 {
59  vp8->sequence_ok = 0;
60  av_log(ctx, AV_LOG_WARNING, "%s", msg);
61  ffio_free_dyn_buf(&vp8->data);
62  return AVERROR(EAGAIN);
63 }
64 
66  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
67  const uint8_t *buf, int len, uint16_t seq,
68  int flags)
69 {
70  int start_partition, end_packet;
71  int extended_bits, part_id;
72  int pictureid_present = 0, tl0picidx_present = 0, tid_present = 0,
73  keyidx_present = 0;
74  int pictureid = -1, pictureid_mask = 0;
75  int returned_old_frame = 0;
76  uint32_t old_timestamp = 0;
77 
78  if (!buf) {
79  if (vp8->data) {
80  int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
81  if (ret < 0)
82  return ret;
83  *timestamp = vp8->timestamp;
84  if (vp8->sequence_dirty)
85  pkt->flags |= AV_PKT_FLAG_CORRUPT;
86  return 0;
87  }
88  return AVERROR(EAGAIN);
89  }
90 
91  if (len < 1)
92  return AVERROR_INVALIDDATA;
93 
94  extended_bits = buf[0] & 0x80;
95  start_partition = buf[0] & 0x10;
96  part_id = buf[0] & 0x0f;
97  end_packet = flags & RTP_FLAG_MARKER;
98  buf++;
99  len--;
100  if (extended_bits) {
101  if (len < 1)
102  return AVERROR_INVALIDDATA;
103  pictureid_present = buf[0] & 0x80;
104  tl0picidx_present = buf[0] & 0x40;
105  tid_present = buf[0] & 0x20;
106  keyidx_present = buf[0] & 0x10;
107  buf++;
108  len--;
109  }
110  if (pictureid_present) {
111  if (len < 1)
112  return AVERROR_INVALIDDATA;
113  if (buf[0] & 0x80) {
114  if (len < 2)
115  return AVERROR_INVALIDDATA;
116  pictureid = AV_RB16(buf) & 0x7fff;
117  pictureid_mask = 0x7fff;
118  buf += 2;
119  len -= 2;
120  } else {
121  pictureid = buf[0] & 0x7f;
122  pictureid_mask = 0x7f;
123  buf++;
124  len--;
125  }
126  }
127  if (tl0picidx_present) {
128  // Ignoring temporal level zero index
129  buf++;
130  len--;
131  }
132  if (tid_present || keyidx_present) {
133  // Ignoring temporal layer index, layer sync bit and keyframe index
134  buf++;
135  len--;
136  }
137  if (len < 1)
138  return AVERROR_INVALIDDATA;
139 
140  if (start_partition && part_id == 0 && len >= 3) {
141  int res;
142  int non_key = buf[0] & 0x01;
143  if (!non_key) {
144  ffio_free_dyn_buf(&vp8->data);
145  // Keyframe, decoding ok again
146  vp8->sequence_ok = 1;
147  vp8->sequence_dirty = 0;
148  vp8->got_keyframe = 1;
149  } else {
150  int can_continue = vp8->data && !vp8->is_keyframe &&
151  avio_tell(vp8->data) >= vp8->first_part_size;
152  if (!vp8->sequence_ok)
153  return AVERROR(EAGAIN);
154  if (!vp8->got_keyframe)
155  return vp8_broken_sequence(ctx, vp8, "Keyframe missing\n");
156  if (pictureid >= 0) {
157  if (pictureid != ((vp8->prev_pictureid + 1) & pictureid_mask)) {
158  return vp8_broken_sequence(ctx, vp8,
159  "Missed a picture, sequence broken\n");
160  } else {
161  if (vp8->data && !can_continue)
162  return vp8_broken_sequence(ctx, vp8,
163  "Missed a picture, sequence broken\n");
164  }
165  } else {
166  uint16_t expected_seq = vp8->prev_seq + 1;
167  int16_t diff = seq - expected_seq;
168  if (vp8->data) {
169  // No picture id, so we can't know if missed packets
170  // contained any new frames. If diff == 0, we did get
171  // later packets from the same frame (matching timestamp),
172  // so we know we didn't miss any frame. If diff == 1 and
173  // we still have data (not flushed by the end of frame
174  // marker), the single missed packet must have been part
175  // of the same frame.
176  if ((diff == 0 || diff == 1) && can_continue) {
177  // Proceed with what we have
178  } else {
179  return vp8_broken_sequence(ctx, vp8,
180  "Missed too much, sequence broken\n");
181  }
182  } else {
183  if (diff != 0)
184  return vp8_broken_sequence(ctx, vp8,
185  "Missed unknown data, sequence broken\n");
186  }
187  }
188  if (vp8->data) {
189  vp8->sequence_dirty = 1;
190  if (avio_tell(vp8->data) >= vp8->first_part_size) {
191  int ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
192  if (ret < 0)
193  return ret;
194  pkt->flags |= AV_PKT_FLAG_CORRUPT;
195  returned_old_frame = 1;
196  old_timestamp = vp8->timestamp;
197  } else {
198  // Shouldn't happen
199  ffio_free_dyn_buf(&vp8->data);
200  }
201  }
202  }
203  vp8->first_part_size = (AV_RL16(&buf[1]) << 3 | buf[0] >> 5) + 3;
204  if ((res = avio_open_dyn_buf(&vp8->data)) < 0)
205  return res;
206  vp8->timestamp = *timestamp;
207  vp8->broken_frame = 0;
208  vp8->prev_pictureid = pictureid;
209  vp8->is_keyframe = !non_key;
210  } else {
211  uint16_t expected_seq = vp8->prev_seq + 1;
212 
213  if (!vp8->sequence_ok)
214  return AVERROR(EAGAIN);
215 
216  if (vp8->timestamp != *timestamp) {
217  // Missed the start of the new frame, sequence broken
218  return vp8_broken_sequence(ctx, vp8,
219  "Received no start marker; dropping frame\n");
220  }
221 
222  if (seq != expected_seq) {
223  if (vp8->is_keyframe) {
224  return vp8_broken_sequence(ctx, vp8,
225  "Missed part of a keyframe, sequence broken\n");
226  } else if (vp8->data && avio_tell(vp8->data) >= vp8->first_part_size) {
227  vp8->broken_frame = 1;
228  vp8->sequence_dirty = 1;
229  } else {
230  return vp8_broken_sequence(ctx, vp8,
231  "Missed part of the first partition, sequence broken\n");
232  }
233  }
234  }
235 
236  if (!vp8->data)
237  return vp8_broken_sequence(ctx, vp8, "Received no start marker\n");
238 
239  vp8->prev_seq = seq;
240  if (!vp8->broken_frame)
241  avio_write(vp8->data, buf, len);
242 
243  if (returned_old_frame) {
244  *timestamp = old_timestamp;
245  return end_packet ? 1 : 0;
246  }
247 
248  if (end_packet) {
249  int ret;
250  ret = ff_rtp_finalize_packet(pkt, &vp8->data, st->index);
251  if (ret < 0)
252  return ret;
253  if (vp8->sequence_dirty)
254  pkt->flags |= AV_PKT_FLAG_CORRUPT;
255  if (vp8->is_keyframe)
256  pkt->flags |= AV_PKT_FLAG_KEY;
257  return 0;
258  }
259 
260  return AVERROR(EAGAIN);
261 }
262 
263 static av_cold int vp8_init(AVFormatContext *s, int st_index, PayloadContext *vp8)
264 {
265  vp8->sequence_ok = 1;
266  return 0;
267 }
268 
270 {
271  ffio_free_dyn_buf(&vp8->data);
272 }
273 
275 {
276  return vp8->sequence_dirty || !vp8->sequence_ok;
277 }
278 
280  .enc_name = "VP8",
281  .codec_type = AVMEDIA_TYPE_VIDEO,
282  .codec_id = AV_CODEC_ID_VP8,
283  .priv_data_size = sizeof(PayloadContext),
284  .init = vp8_init,
285  .close = vp8_close_context,
287  .need_keyframe = vp8_need_keyframe,
288 };
static void vp8_close_context(PayloadContext *vp8)
Definition: rtpdec_vp8.c:269
AVPacket pkt
Definition: rtpdec_qt.c:37
Bytestream IO Context.
Definition: avio.h:161
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index, int flush)
Parse a packet, add all split parts to parse_queue.
Definition: utils.c:1447
RTP/JPEG specific private data.
Definition: rdt.c:83
int index
stream index in AVFormatContext
Definition: avformat.h:882
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
int first_part_size
Definition: rtpdec_vp8.c:44
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:87
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1430
uint16_t prev_seq
Definition: rtpdec_vp8.c:45
Format I/O context.
Definition: avformat.h:1358
uint8_t
#define av_cold
Definition: attributes.h:82
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
#define av_log(a,...)
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1512
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
#define RTP_FLAG_MARKER
RTP marker bit was set for this packet.
Definition: rtpdec.h:93
static int vp8_handle_packet(AVFormatContext *ctx, PayloadContext *vp8, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
Definition: rtpdec_vp8.c:65
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1486
static int vp8_need_keyframe(PayloadContext *vp8)
Definition: rtpdec_vp8.c:274
AVFormatContext * ctx
Definition: movenc.c:48
int prev_pictureid
Definition: rtpdec_vp8.c:46
#define s(width, name)
Definition: cbs_vp9.c:257
int sequence_dirty
Definition: rtpdec_vp8.c:52
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1489
Stream structure.
Definition: avformat.h:881
AVIOContext * data
Definition: rtpdec_vp8.c:36
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:183
const char * enc_name
Definition: rtpdec.h:116
#define flags(name, subs,...)
Definition: cbs_av1.c:561
const RTPDynamicProtocolHandler ff_vp8_dynamic_handler
Definition: rtpdec_vp8.c:279
static int vp8_broken_sequence(AVFormatContext *ctx, PayloadContext *vp8, const char *msg)
Definition: rtpdec_vp8.c:56
static av_cold int vp8_init(AVFormatContext *s, int st_index, PayloadContext *vp8)
Definition: rtpdec_vp8.c:263
#define AV_PKT_FLAG_CORRUPT
The packet content is corrupted.
Definition: avcodec.h:1513
int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx)
Close the dynamic buffer and make a packet from it.
Definition: rtpdec.c:927
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
This structure stores compressed data.
Definition: avcodec.h:1457