FFmpeg
dirac_parser.c
Go to the documentation of this file.
1 /*
2  * Dirac parser
3  *
4  * Copyright (c) 2007-2008 Marco Gerards <marco@gnu.org>
5  * Copyright (c) 2008 BBC, Anuradha Suraparaju <asuraparaju@gmail.com>
6  *
7  * This file is part of FFmpeg.
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 /**
25  * @file
26  * Dirac Parser
27  * @author Marco Gerards <marco@gnu.org>
28  */
29 
30 #include <string.h>
31 
32 #include "libavutil/intreadwrite.h"
33 #include "libavutil/mem.h"
34 
35 #include "parser.h"
36 
37 #define DIRAC_PARSE_INFO_PREFIX 0x42424344
38 
39 /**
40  * Find the end of the current frame in the bitstream.
41  * @return the position of the first byte of the next frame or -1
42  */
43 typedef struct DiracParseContext {
44  int state;
45  int is_synced;
50  int index;
55 
57  const uint8_t *buf, int buf_size)
58 {
59  uint32_t state = pc->state;
60  int i = 0;
61 
62  if (!pc->is_synced) {
63  for (i = 0; i < buf_size; i++) {
64  state = (state << 8) | buf[i];
65  if (state == DIRAC_PARSE_INFO_PREFIX) {
66  state = -1;
67  pc->is_synced = 1;
68  pc->header_bytes_needed = 9;
69  pc->sync_offset = i;
70  break;
71  }
72  }
73  }
74 
75  if (pc->is_synced) {
76  pc->sync_offset = 0;
77  for (; i < buf_size; i++) {
78  if (state == DIRAC_PARSE_INFO_PREFIX) {
79  if ((buf_size - i) >= pc->header_bytes_needed) {
80  pc->state = -1;
81  return i + pc->header_bytes_needed;
82  } else {
83  pc->header_bytes_needed = 9 - (buf_size - i);
84  break;
85  }
86  } else
87  state = (state << 8) | buf[i];
88  }
89  }
90  pc->state = state;
91  return -1;
92 }
93 
94 typedef struct DiracParseUnit {
99 
101  int offset)
102 {
103  int i;
104  int8_t *start;
105  static const uint8_t valid_pu_types[] = {
106  0x00, 0x10, 0x20, 0x30, 0x08, 0x48, 0xC8, 0xE8, 0x0A, 0x0C, 0x0D, 0x0E,
107  0x4C, 0x09, 0xCC, 0x88, 0xCB
108  };
109 
110  if (offset < 0 || pc->index - 13 < offset)
111  return 0;
112 
113  start = pc->buffer + offset;
114  pu->pu_type = start[4];
115 
116  pu->next_pu_offset = AV_RB32(start + 5);
117  pu->prev_pu_offset = AV_RB32(start + 9);
118 
119  /* Check for valid parse code */
120  for (i = 0; i < 17; i++)
121  if (valid_pu_types[i] == pu->pu_type)
122  break;
123  if (i == 17)
124  return 0;
125 
126  if (pu->pu_type == 0x10 && pu->next_pu_offset == 0x00)
127  pu->next_pu_offset = 13; /* The length of a parse info header */
128 
129  /* Check if the parse offsets are somewhat sane */
130  if ((pu->next_pu_offset && pu->next_pu_offset < 13) ||
131  (pu->prev_pu_offset && pu->prev_pu_offset < 13))
132  return 0;
133 
134  return 1;
135 }
136 
138  int next, const uint8_t **buf, int *buf_size)
139 {
140  int parse_timing_info = (s->pts == AV_NOPTS_VALUE &&
141  s->dts == AV_NOPTS_VALUE);
142  DiracParseContext *pc = s->priv_data;
143 
144  if (pc->overread_index) {
145  memmove(pc->buffer, pc->buffer + pc->overread_index,
146  pc->index - pc->overread_index);
147  pc->index -= pc->overread_index;
148  pc->overread_index = 0;
149  if (*buf_size == 0 && pc->buffer[4] == 0x10) {
150  *buf = pc->buffer;
151  *buf_size = pc->index;
152  return 0;
153  }
154  }
155 
156  if (next == -1) {
157  /* Found a possible frame start but not a frame end */
158  void *new_buffer =
160  pc->index + (*buf_size - pc->sync_offset));
161  if (!new_buffer)
162  return AVERROR(ENOMEM);
163  pc->buffer = new_buffer;
164  memcpy(pc->buffer + pc->index, (*buf + pc->sync_offset),
165  *buf_size - pc->sync_offset);
166  pc->index += *buf_size - pc->sync_offset;
167  return -1;
168  } else {
169  /* Found a possible frame start and a possible frame end */
170  DiracParseUnit pu1, pu;
171  void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size,
172  pc->index + next);
173  if (!new_buffer)
174  return AVERROR(ENOMEM);
175  pc->buffer = new_buffer;
176  memcpy(pc->buffer + pc->index, *buf, next);
177  pc->index += next;
178 
179  /* Need to check if we have a valid Parse Unit. We can't go by the
180  * sync pattern 'BBCD' alone because arithmetic coding of the residual
181  * and motion data can cause the pattern triggering a false start of
182  * frame. So check if the previous parse offset of the next parse unit
183  * is equal to the next parse offset of the current parse unit then
184  * we can be pretty sure that we have a valid parse unit */
185  if (!unpack_parse_unit(&pu1, pc, pc->index - 13) ||
186  !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) ||
187  pu.next_pu_offset != pu1.prev_pu_offset ||
188  pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset
189  ) {
190  pc->index -= 9;
191  *buf_size = next - 9;
192  pc->header_bytes_needed = 9;
193  return -1;
194  }
195 
196  /* All non-frame data must be accompanied by frame data. This is to
197  * ensure that pts is set correctly. So if the current parse unit is
198  * not frame data, wait for frame data to come along */
199 
200  pc->dirac_unit = pc->buffer + pc->index - 13 -
202 
204 
205  if ((pu.pu_type & 0x08) != 0x08) {
206  pc->header_bytes_needed = 9;
207  *buf_size = next;
208  return -1;
209  }
210 
211  /* Get the picture number to set the pts and dts*/
212  if (parse_timing_info && pu1.prev_pu_offset >= 13) {
213  uint8_t *cur_pu = pc->buffer +
214  pc->index - 13 - pu1.prev_pu_offset;
215  int64_t pts = AV_RB32(cur_pu + 13);
216  if (s->last_pts == 0 && s->last_dts == 0)
217  s->dts = pts - 1;
218  else
219  s->dts = s->last_dts + 1;
220  s->pts = pts;
221  if (!avctx->has_b_frames && (cur_pu[4] & 0x03))
222  avctx->has_b_frames = 1;
223  }
224  if (avctx->has_b_frames && s->pts == s->dts)
226 
227  /* Finally have a complete Dirac data unit */
228  *buf = pc->dirac_unit;
229  *buf_size = pc->dirac_unit_size;
230 
231  pc->dirac_unit_size = 0;
232  pc->overread_index = pc->index - 13;
233  pc->header_bytes_needed = 9;
234  }
235  return next;
236 }
237 
239  const uint8_t **poutbuf, int *poutbuf_size,
240  const uint8_t *buf, int buf_size)
241 {
242  DiracParseContext *pc = s->priv_data;
243  int next;
244 
245  *poutbuf = NULL;
246  *poutbuf_size = 0;
247 
249  next = buf_size;
250  *poutbuf = buf;
251  *poutbuf_size = buf_size;
252  /* Assume that data has been packetized into an encapsulation unit. */
253  } else {
254  next = find_frame_end(pc, buf, buf_size);
255  if (!pc->is_synced && next == -1)
256  /* No frame start found yet. So throw away the entire buffer. */
257  return buf_size;
258 
259  if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0)
260  return buf_size;
261  }
262 
263  *poutbuf = buf;
264  *poutbuf_size = buf_size;
265  return next;
266 }
267 
269 {
270  DiracParseContext *pc = s->priv_data;
271 
272  if (pc->buffer_size > 0)
273  av_freep(&pc->buffer);
274 }
275 
278  .priv_data_size = sizeof(DiracParseContext),
279  .parser_parse = dirac_parse,
280  .parser_close = dirac_parse_close,
281 };
#define NULL
Definition: coverity.c:32
Memory handling functions.
int codec_ids[5]
Definition: avcodec.h:5287
uint8_t * buffer
Definition: dirac_parser.c:51
uint8_t
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
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_RB32
Definition: bytestream.h:87
static int find_frame_end(DiracParseContext *pc, const uint8_t *buf, int buf_size)
Definition: dirac_parser.c:56
AVCodecParser ff_dirac_parser
Definition: dirac_parser.c:276
uint8_t pu_type
Definition: dirac_parser.c:97
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
int has_b_frames
Size of the frame reordering buffer in the decoder.
Definition: avcodec.h:1858
static void dirac_parse_close(AVCodecParserContext *s)
Definition: dirac_parser.c:268
static int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc, int offset)
Definition: dirac_parser.c:100
#define s(width, name)
Definition: cbs_vp9.c:257
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:476
uint8_t * dirac_unit
Definition: dirac_parser.c:53
main external API structure.
Definition: avcodec.h:1568
void * buf
Definition: avisynth_c.h:766
static int dirac_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size)
Definition: dirac_parser.c:238
static int64_t pts
#define DIRAC_PARSE_INFO_PREFIX
Definition: dirac_parser.c:37
Bi-dir predicted.
Definition: avutil.h:276
#define PARSER_FLAG_COMPLETE_FRAMES
Definition: avcodec.h:5153
Find the end of the current frame in the bitstream.
Definition: dirac_parser.c:43
static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, int next, const uint8_t **buf, int *buf_size)
Definition: dirac_parser.c:137
#define av_freep(p)
void INT64 start
Definition: avisynth_c.h:766
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
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248