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 "libavutil/intreadwrite.h"
31 
32 #include "avio_internal.h"
33 #include "rtpdec.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)
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;
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)
255  if (vp8->is_keyframe)
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 };
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVERROR
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
PayloadContext::sequence_dirty
int sequence_dirty
Definition: rtpdec_vp8.c:52
vp8_close_context
static void vp8_close_context(PayloadContext *vp8)
Definition: rtpdec_vp8.c:269
PayloadContext::sequence_ok
int sequence_ok
Definition: rtpdec_vp8.c:43
RTP_FLAG_MARKER
#define RTP_FLAG_MARKER
RTP marker bit was set for this packet.
Definition: rtpdec.h:94
ff_vp8_dynamic_handler
const RTPDynamicProtocolHandler ff_vp8_dynamic_handler
Definition: rtpdec_vp8.c:279
PayloadContext::prev_pictureid
int prev_pictureid
Definition: rtpdec_vp8.c:46
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:577
ff_rtp_finalize_packet
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:1002
PayloadContext::timestamp
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
RTPDynamicProtocolHandler::enc_name
const char * enc_name
Definition: rtpdec.h:117
vp8_need_keyframe
static int vp8_need_keyframe(PayloadContext *vp8)
Definition: rtpdec_vp8.c:274
avio_tell
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:494
pkt
AVPacket * pkt
Definition: movenc.c:59
av_cold
#define av_cold
Definition: attributes.h:90
AV_PKT_FLAG_CORRUPT
#define AV_PKT_FLAG_CORRUPT
The packet content is corrupted.
Definition: packet.h:578
avio_open_dyn_buf
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1361
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
PayloadContext::data
AVIOContext * data
Definition: rtpdec_vp8.c:36
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AV_RL16
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:94
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
PayloadContext::prev_seq
uint16_t prev_seq
Definition: rtpdec_vp8.c:45
vp8_broken_sequence
static int vp8_broken_sequence(AVFormatContext *ctx, PayloadContext *vp8, const char *msg)
Definition: rtpdec_vp8.c:56
rtpdec.h
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts.c:365
diff
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
Definition: vf_paletteuse.c:164
avio_write
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:200
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:528
PayloadContext::broken_frame
int broken_frame
Definition: rtpdec_vp8.c:47
avio_internal.h
len
int len
Definition: vorbis_enc_data.h:426
ffio_free_dyn_buf
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1434
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:743
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:749
PayloadContext::first_part_size
int first_part_size
Definition: rtpdec_vp8.c:44
vp8_handle_packet
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
parse_packet
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index, int flush)
Parse a packet, add all split parts to parse_queue.
Definition: demux.c:1154
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVPacket
This structure stores compressed data.
Definition: packet.h:499
AV_CODEC_ID_VP8
@ AV_CODEC_ID_VP8
Definition: codec_id.h:192
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
PayloadContext::is_keyframe
int is_keyframe
Definition: rtpdec_vp8.c:38
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
PayloadContext::got_keyframe
int got_keyframe
Definition: rtpdec_vp8.c:53
vp8_init
static av_cold int vp8_init(AVFormatContext *s, int st_index, PayloadContext *vp8)
Definition: rtpdec_vp8.c:263
PayloadContext
RTP/JPEG specific private data.
Definition: rdt.c:84
RTPDynamicProtocolHandler
Definition: rtpdec.h:116
AV_RB16
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:98