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];
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++) {
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 if (s->last_dts != AV_NOPTS_VALUE)
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)
225  s->pict_type = AV_PICTURE_TYPE_B;
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 
248  if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
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 };
DiracParseUnit
Definition: dirac_parser.c:94
DiracParseContext::dirac_unit_size
int dirac_unit_size
Definition: dirac_parser.c:52
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
dirac_combine_frame
static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, int next, const uint8_t **buf, int *buf_size)
Definition: dirac_parser.c:137
DiracParseContext::buffer
uint8_t * buffer
Definition: dirac_parser.c:51
AV_CODEC_ID_DIRAC
@ AV_CODEC_ID_DIRAC
Definition: codec_id.h:165
state
static struct @321 state
index
fg index
Definition: ffmpeg_filter.c:170
ff_dirac_parser
AVCodecParser ff_dirac_parser
Definition: dirac_parser.c:276
DiracParseUnit::next_pu_offset
int next_pu_offset
Definition: dirac_parser.c:95
pts
static int64_t pts
Definition: transcode_aac.c:652
AVCodecContext::has_b_frames
int has_b_frames
Size of the frame reordering buffer in the decoder.
Definition: avcodec.h:826
av_fast_realloc
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:478
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:257
dirac_parse_close
static void dirac_parse_close(AVCodecParserContext *s)
Definition: dirac_parser.c:268
DiracParseContext::state
int state
Definition: dirac_parser.c:44
DiracParseContext::buffer_size
int buffer_size
Definition: dirac_parser.c:49
DiracParseContext::sync_offset
int sync_offset
Definition: dirac_parser.c:46
find_frame_end
static int find_frame_end(DiracParseContext *pc, const uint8_t *buf, int buf_size)
Definition: dirac_parser.c:56
NULL
#define NULL
Definition: coverity.c:32
AVCodecParser::codec_ids
int codec_ids[5]
Definition: avcodec.h:3545
DiracParseContext::header_bytes_needed
int header_bytes_needed
Definition: dirac_parser.c:47
DiracParseContext::overread_index
int overread_index
Definition: dirac_parser.c:48
DiracParseContext::index
int index
Definition: dirac_parser.c:50
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
AV_RB32
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:96
unpack_parse_unit
static int unpack_parse_unit(DiracParseUnit *pu, DiracParseContext *pc, int offset)
Definition: dirac_parser.c:100
DiracParseContext
Find the end of the current frame in the bitstream.
Definition: dirac_parser.c:43
offset
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
Definition: writing_filters.txt:86
DiracParseUnit::pu_type
uint8_t pu_type
Definition: dirac_parser.c:97
DiracParseContext::dirac_unit
uint8_t * dirac_unit
Definition: dirac_parser.c:53
i
int i
Definition: input.c:407
dirac_parse
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
PARSER_FLAG_COMPLETE_FRAMES
#define PARSER_FLAG_COMPLETE_FRAMES
Definition: avcodec.h:3411
uint8_t
uint8_t
Definition: audio_convert.c:194
parser.h
AVCodecParserContext
Definition: avcodec.h:3377
AVCodecContext
main external API structure.
Definition: avcodec.h:536
DiracParseContext::is_synced
int is_synced
Definition: dirac_parser.c:45
AV_PICTURE_TYPE_B
@ AV_PICTURE_TYPE_B
Bi-dir predicted.
Definition: avutil.h:276
DIRAC_PARSE_INFO_PREFIX
#define DIRAC_PARSE_INFO_PREFIX
Definition: dirac_parser.c:37
mem.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AVCodecParser
Definition: avcodec.h:3544
DiracParseUnit::prev_pu_offset
int prev_pu_offset
Definition: dirac_parser.c:96