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/attributes.h"
33 #include "libavutil/intreadwrite.h"
34 #include "libavutil/mem.h"
35 
36 #include "avcodec.h"
37 #include "parser_internal.h"
38 
39 #define DIRAC_PARSE_INFO_PREFIX 0x42424344
40 
41 /**
42  * Find the end of the current frame in the bitstream.
43  * @return the position of the first byte of the next frame or -1
44  */
45 typedef struct DiracParseContext {
46  int state;
47  int is_synced;
52  int index;
53  uint8_t *buffer;
55  uint8_t *dirac_unit;
57 
59  const uint8_t *buf, int buf_size)
60 {
61  uint32_t state = pc->state;
62  int i = 0;
63 
64  if (!pc->is_synced) {
65  for (i = 0; i < buf_size; i++) {
66  state = (state << 8) | buf[i];
68  state = -1;
69  pc->is_synced = 1;
70  pc->header_bytes_needed = 9;
71  pc->sync_offset = i;
72  break;
73  }
74  }
75  }
76 
77  if (pc->is_synced) {
78  pc->sync_offset = 0;
79  for (; i < buf_size; i++) {
81  if ((buf_size - i) >= pc->header_bytes_needed) {
82  pc->state = -1;
83  return i + pc->header_bytes_needed;
84  } else {
85  pc->header_bytes_needed = 9 - (buf_size - i);
86  break;
87  }
88  } else
89  state = (state << 8) | buf[i];
90  }
91  }
92  pc->state = state;
93  return -1;
94 }
95 
96 typedef struct DiracParseUnit {
99  uint8_t pu_type;
101 
103  int offset)
104 {
105  int i;
106  int8_t *start;
107  static const uint8_t valid_pu_types[] = {
108  0x00, 0x10, 0x20, 0x30, 0x08, 0x48, 0xC8, 0xE8, 0x0A, 0x0C, 0x0D, 0x0E,
109  0x4C, 0x09, 0xCC, 0x88, 0xCB
110  };
111 
112  if (offset < 0 || pc->index - 13 < offset)
113  return 0;
114 
115  start = pc->buffer + offset;
116  pu->pu_type = start[4];
117 
118  pu->next_pu_offset = AV_RB32(start + 5);
119  pu->prev_pu_offset = AV_RB32(start + 9);
120 
121  /* Check for valid parse code */
122  for (i = 0; i < 17; i++)
123  if (valid_pu_types[i] == pu->pu_type)
124  break;
125  if (i == 17)
126  return 0;
127 
128  if (pu->pu_type == 0x10 && pu->next_pu_offset == 0x00)
129  pu->next_pu_offset = 13; /* The length of a parse info header */
130 
131  /* Check if the parse offsets are somewhat sane */
132  if ((pu->next_pu_offset && pu->next_pu_offset < 13) ||
133  (pu->prev_pu_offset && pu->prev_pu_offset < 13))
134  return 0;
135 
136  return 1;
137 }
138 
140  int next, const uint8_t **buf, int *buf_size)
141 {
142  int parse_timing_info = (s->pts == AV_NOPTS_VALUE &&
143  s->dts == AV_NOPTS_VALUE);
144  DiracParseContext *pc = s->priv_data;
145 
146  if (pc->overread_index) {
147  memmove(pc->buffer, pc->buffer + pc->overread_index,
148  pc->index - pc->overread_index);
149  pc->index -= pc->overread_index;
150  pc->overread_index = 0;
151  if (*buf_size == 0 && pc->buffer[4] == 0x10) {
152  *buf = pc->buffer;
153  *buf_size = pc->index;
154  return 0;
155  }
156  }
157 
158  if (next == -1) {
159  /* Found a possible frame start but not a frame end */
160  void *new_buffer =
162  pc->index + (*buf_size - pc->sync_offset));
163  if (!new_buffer)
164  return AVERROR(ENOMEM);
165  pc->buffer = new_buffer;
166  memcpy(pc->buffer + pc->index, (*buf + pc->sync_offset),
167  *buf_size - pc->sync_offset);
168  pc->index += *buf_size - pc->sync_offset;
169  return -1;
170  } else {
171  /* Found a possible frame start and a possible frame end */
172  DiracParseUnit pu1, pu;
173  void *new_buffer = av_fast_realloc(pc->buffer, &pc->buffer_size,
174  pc->index + next);
175  if (!new_buffer)
176  return AVERROR(ENOMEM);
177  pc->buffer = new_buffer;
178  memcpy(pc->buffer + pc->index, *buf, next);
179  pc->index += next;
180 
181  /* Need to check if we have a valid Parse Unit. We can't go by the
182  * sync pattern 'BBCD' alone because arithmetic coding of the residual
183  * and motion data can cause the pattern triggering a false start of
184  * frame. So check if the previous parse offset of the next parse unit
185  * is equal to the next parse offset of the current parse unit then
186  * we can be pretty sure that we have a valid parse unit */
187  if (!unpack_parse_unit(&pu1, pc, pc->index - 13) ||
188  !unpack_parse_unit(&pu, pc, pc->index - 13 - pu1.prev_pu_offset) ||
189  pu.next_pu_offset != pu1.prev_pu_offset ||
190  pc->index < pc->dirac_unit_size + 13LL + pu1.prev_pu_offset
191  ) {
192  pc->index -= 9;
193  *buf_size = next - 9;
194  pc->header_bytes_needed = 9;
195  return -1;
196  }
197 
198  /* All non-frame data must be accompanied by frame data. This is to
199  * ensure that pts is set correctly. So if the current parse unit is
200  * not frame data, wait for frame data to come along */
201 
202  pc->dirac_unit = pc->buffer + pc->index - 13 -
204 
206 
207  if ((pu.pu_type & 0x08) != 0x08) {
208  pc->header_bytes_needed = 9;
209  *buf_size = next;
210  return -1;
211  }
212 
213  /* Get the picture number to set the pts and dts*/
214  if (parse_timing_info && pu1.prev_pu_offset >= 13) {
215  uint8_t *cur_pu = pc->buffer +
216  pc->index - 13 - pu1.prev_pu_offset;
217  int64_t pts = AV_RB32(cur_pu + 13);
218  if (s->last_pts == 0 && s->last_dts == 0)
219  s->dts = pts - 1;
220  else if (s->last_dts != AV_NOPTS_VALUE)
221  s->dts = s->last_dts + 1;
222  s->pts = pts;
223  if (!avctx->has_b_frames && (cur_pu[4] & 0x03))
224  avctx->has_b_frames = 1;
225  }
226  if (avctx->has_b_frames && s->pts == s->dts)
227  s->pict_type = AV_PICTURE_TYPE_B;
228 
229  /* Finally have a complete Dirac data unit */
230  *buf = pc->dirac_unit;
231  *buf_size = pc->dirac_unit_size;
232 
233  pc->dirac_unit_size = 0;
234  pc->overread_index = pc->index - 13;
235  pc->header_bytes_needed = 9;
236  }
237  return next;
238 }
239 
241  const uint8_t **poutbuf, int *poutbuf_size,
242  const uint8_t *buf, int buf_size)
243 {
244  DiracParseContext *pc = s->priv_data;
245  int next;
246 
247  *poutbuf = NULL;
248  *poutbuf_size = 0;
249 
250  if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
251  next = buf_size;
252  *poutbuf = buf;
253  *poutbuf_size = buf_size;
254  /* Assume that data has been packetized into an encapsulation unit. */
255  } else {
256  next = find_frame_end(pc, buf, buf_size);
257  if (!pc->is_synced && next == -1)
258  /* No frame start found yet. So throw away the entire buffer. */
259  return buf_size;
260 
261  if (dirac_combine_frame(s, avctx, next, &buf, &buf_size) < 0)
262  return buf_size;
263  }
264 
265  *poutbuf = buf;
266  *poutbuf_size = buf_size;
267  return next;
268 }
269 
271 {
272  DiracParseContext *pc = s->priv_data;
273 
274  if (pc->buffer_size > 0)
275  av_freep(&pc->buffer);
276 }
277 
280  .priv_data_size = sizeof(DiracParseContext),
281  .parse = dirac_parse,
283 };
DiracParseUnit
Definition: dirac_parser.c:96
DiracParseContext::dirac_unit_size
int dirac_unit_size
Definition: dirac_parser.c:54
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:139
dirac_parse_close
static av_cold void dirac_parse_close(AVCodecParserContext *s)
Definition: dirac_parser.c:270
DiracParseContext::buffer
uint8_t * buffer
Definition: dirac_parser.c:53
AV_CODEC_ID_DIRAC
@ AV_CODEC_ID_DIRAC
Definition: codec_id.h:168
int64_t
long long int64_t
Definition: coverity.c:34
parser_internal.h
DiracParseUnit::next_pu_offset
int next_pu_offset
Definition: dirac_parser.c:97
close
static av_cold void close(AVCodecParserContext *s)
Definition: apv_parser.c:136
pts
static int64_t pts
Definition: transcode_aac.c:644
av_cold
#define av_cold
Definition: attributes.h:106
AVCodecContext::has_b_frames
int has_b_frames
Size of the frame reordering buffer in the decoder.
Definition: avcodec.h:697
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:497
intreadwrite.h
s
#define s(width, name)
Definition: cbs_vp9.c:198
DiracParseContext::state
int state
Definition: dirac_parser.c:46
DiracParseContext::buffer_size
int buffer_size
Definition: dirac_parser.c:51
DiracParseContext::sync_offset
int sync_offset
Definition: dirac_parser.c:48
find_frame_end
static int find_frame_end(DiracParseContext *pc, const uint8_t *buf, int buf_size)
Definition: dirac_parser.c:58
NULL
#define NULL
Definition: coverity.c:32
DiracParseContext::header_bytes_needed
int header_bytes_needed
Definition: dirac_parser.c:49
state
static struct @541 state
DiracParseContext::overread_index
int overread_index
Definition: dirac_parser.c:50
parse
static int parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size)
Definition: apv_parser.c:46
index
int index
Definition: gxfenc.c:90
DiracParseContext::index
int index
Definition: dirac_parser.c:52
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:247
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:102
DiracParseContext
Find the end of the current frame in the bitstream.
Definition: dirac_parser.c:45
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
attributes.h
FFCodecParser
Definition: parser_internal.h:29
DiracParseUnit::pu_type
uint8_t pu_type
Definition: dirac_parser.c:99
DiracParseContext::dirac_unit
uint8_t * dirac_unit
Definition: dirac_parser.c:55
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:240
PARSER_FLAG_COMPLETE_FRAMES
#define PARSER_FLAG_COMPLETE_FRAMES
Definition: avcodec.h:2609
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
PARSER_CODEC_LIST
#define PARSER_CODEC_LIST(...)
Definition: parser_internal.h:76
avcodec.h
AVCodecParserContext
Definition: avcodec.h:2575
AVCodecContext
main external API structure.
Definition: avcodec.h:431
DiracParseContext::is_synced
int is_synced
Definition: dirac_parser.c:47
AV_PICTURE_TYPE_B
@ AV_PICTURE_TYPE_B
Bi-dir predicted.
Definition: avutil.h:280
DIRAC_PARSE_INFO_PREFIX
#define DIRAC_PARSE_INFO_PREFIX
Definition: dirac_parser.c:39
mem.h
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
DiracParseUnit::prev_pu_offset
int prev_pu_offset
Definition: dirac_parser.c:98
ff_dirac_parser
const FFCodecParser ff_dirac_parser
Definition: dirac_parser.c:278