FFmpeg
kmvc.c
Go to the documentation of this file.
1 /*
2  * KMVC decoder
3  * Copyright (c) 2006 Konstantin Shishkov
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * @file
24  * Karl Morton's Video Codec decoder
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 
30 #include "avcodec.h"
31 #include "bytestream.h"
32 #include "decode.h"
33 #include "internal.h"
34 #include "libavutil/common.h"
35 
36 #define KMVC_KEYFRAME 0x80
37 #define KMVC_PALETTE 0x40
38 #define KMVC_METHOD 0x0F
39 #define MAX_PALSIZE 256
40 
41 /*
42  * Decoder context
43  */
44 typedef struct KmvcContext {
46 
49  int setpal;
50  int palsize;
51  uint32_t pal[MAX_PALSIZE];
52  uint8_t frm0[320 * 200], frm1[320 * 200];
53 } KmvcContext;
54 
55 typedef struct BitBuf {
56  int bits;
57  int bitbuf;
58 } BitBuf;
59 
60 #define BLK(data, x, y) data[av_clip((x) + (y) * 320, 0, 320 * 200 -1)]
61 
62 #define kmvc_init_getbits(bb, g) bb.bits = 7; bb.bitbuf = bytestream2_get_byte(g);
63 
64 #define kmvc_getbit(bb, g, res) {\
65  res = 0; \
66  if (bb.bitbuf & (1 << bb.bits)) res = 1; \
67  bb.bits--; \
68  if(bb.bits == -1) { \
69  bb.bitbuf = bytestream2_get_byte(g); \
70  bb.bits = 7; \
71  } \
72 }
73 
74 static int kmvc_decode_intra_8x8(KmvcContext * ctx, int w, int h)
75 {
76  BitBuf bb;
77  int res, val;
78  int i, j;
79  int bx, by;
80  int l0x, l1x, l0y, l1y;
81  int mx, my;
82 
83  kmvc_init_getbits(bb, &ctx->g);
84 
85  for (by = 0; by < h; by += 8)
86  for (bx = 0; bx < w; bx += 8) {
87  if (!bytestream2_get_bytes_left(&ctx->g)) {
88  av_log(ctx->avctx, AV_LOG_ERROR, "Data overrun\n");
89  return AVERROR_INVALIDDATA;
90  }
91  kmvc_getbit(bb, &ctx->g, res);
92  if (!res) { // fill whole 8x8 block
93  val = bytestream2_get_byte(&ctx->g);
94  for (i = 0; i < 64; i++)
95  BLK(ctx->cur, bx + (i & 0x7), by + (i >> 3)) = val;
96  } else { // handle four 4x4 subblocks
97  for (i = 0; i < 4; i++) {
98  l0x = bx + (i & 1) * 4;
99  l0y = by + (i & 2) * 2;
100  kmvc_getbit(bb, &ctx->g, res);
101  if (!res) {
102  kmvc_getbit(bb, &ctx->g, res);
103  if (!res) { // fill whole 4x4 block
104  val = bytestream2_get_byte(&ctx->g);
105  for (j = 0; j < 16; j++)
106  BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) = val;
107  } else { // copy block from already decoded place
108  val = bytestream2_get_byte(&ctx->g);
109  mx = val & 0xF;
110  my = val >> 4;
111  if ((l0x-mx) + 320*(l0y-my) < 0 || (l0x-mx) + 320*(l0y-my) > 320*197 - 4) {
112  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
113  return AVERROR_INVALIDDATA;
114  }
115  for (j = 0; j < 16; j++)
116  BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) =
117  BLK(ctx->cur, l0x + (j & 3) - mx, l0y + (j >> 2) - my);
118  }
119  } else { // descend to 2x2 sub-sub-blocks
120  for (j = 0; j < 4; j++) {
121  l1x = l0x + (j & 1) * 2;
122  l1y = l0y + (j & 2);
123  kmvc_getbit(bb, &ctx->g, res);
124  if (!res) {
125  kmvc_getbit(bb, &ctx->g, res);
126  if (!res) { // fill whole 2x2 block
127  val = bytestream2_get_byte(&ctx->g);
128  BLK(ctx->cur, l1x, l1y) = val;
129  BLK(ctx->cur, l1x + 1, l1y) = val;
130  BLK(ctx->cur, l1x, l1y + 1) = val;
131  BLK(ctx->cur, l1x + 1, l1y + 1) = val;
132  } else { // copy block from already decoded place
133  val = bytestream2_get_byte(&ctx->g);
134  mx = val & 0xF;
135  my = val >> 4;
136  if ((l1x-mx) + 320*(l1y-my) < 0 || (l1x-mx) + 320*(l1y-my) > 320*199 - 2) {
137  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
138  return AVERROR_INVALIDDATA;
139  }
140  BLK(ctx->cur, l1x, l1y) = BLK(ctx->cur, l1x - mx, l1y - my);
141  BLK(ctx->cur, l1x + 1, l1y) =
142  BLK(ctx->cur, l1x + 1 - mx, l1y - my);
143  BLK(ctx->cur, l1x, l1y + 1) =
144  BLK(ctx->cur, l1x - mx, l1y + 1 - my);
145  BLK(ctx->cur, l1x + 1, l1y + 1) =
146  BLK(ctx->cur, l1x + 1 - mx, l1y + 1 - my);
147  }
148  } else { // read values for block
149  BLK(ctx->cur, l1x, l1y) = bytestream2_get_byte(&ctx->g);
150  BLK(ctx->cur, l1x + 1, l1y) = bytestream2_get_byte(&ctx->g);
151  BLK(ctx->cur, l1x, l1y + 1) = bytestream2_get_byte(&ctx->g);
152  BLK(ctx->cur, l1x + 1, l1y + 1) = bytestream2_get_byte(&ctx->g);
153  }
154  }
155  }
156  }
157  }
158  }
159 
160  return 0;
161 }
162 
163 static int kmvc_decode_inter_8x8(KmvcContext * ctx, int w, int h)
164 {
165  BitBuf bb;
166  int res, val;
167  int i, j;
168  int bx, by;
169  int l0x, l1x, l0y, l1y;
170  int mx, my;
171 
172  kmvc_init_getbits(bb, &ctx->g);
173 
174  for (by = 0; by < h; by += 8)
175  for (bx = 0; bx < w; bx += 8) {
176  kmvc_getbit(bb, &ctx->g, res);
177  if (!res) {
178  kmvc_getbit(bb, &ctx->g, res);
179  if (!res) { // fill whole 8x8 block
180  if (!bytestream2_get_bytes_left(&ctx->g)) {
181  av_log(ctx->avctx, AV_LOG_ERROR, "Data overrun\n");
182  return AVERROR_INVALIDDATA;
183  }
184  val = bytestream2_get_byte(&ctx->g);
185  for (i = 0; i < 64; i++)
186  BLK(ctx->cur, bx + (i & 0x7), by + (i >> 3)) = val;
187  } else { // copy block from previous frame
188  for (i = 0; i < 64; i++)
189  BLK(ctx->cur, bx + (i & 0x7), by + (i >> 3)) =
190  BLK(ctx->prev, bx + (i & 0x7), by + (i >> 3));
191  }
192  } else { // handle four 4x4 subblocks
193  if (!bytestream2_get_bytes_left(&ctx->g)) {
194  av_log(ctx->avctx, AV_LOG_ERROR, "Data overrun\n");
195  return AVERROR_INVALIDDATA;
196  }
197  for (i = 0; i < 4; i++) {
198  l0x = bx + (i & 1) * 4;
199  l0y = by + (i & 2) * 2;
200  kmvc_getbit(bb, &ctx->g, res);
201  if (!res) {
202  kmvc_getbit(bb, &ctx->g, res);
203  if (!res) { // fill whole 4x4 block
204  val = bytestream2_get_byte(&ctx->g);
205  for (j = 0; j < 16; j++)
206  BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) = val;
207  } else { // copy block
208  val = bytestream2_get_byte(&ctx->g);
209  mx = (val & 0xF) - 8;
210  my = (val >> 4) - 8;
211  if ((l0x+mx) + 320*(l0y+my) < 0 || (l0x+mx) + 320*(l0y+my) > 320*197 - 4) {
212  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
213  return AVERROR_INVALIDDATA;
214  }
215  for (j = 0; j < 16; j++)
216  BLK(ctx->cur, l0x + (j & 3), l0y + (j >> 2)) =
217  BLK(ctx->prev, l0x + (j & 3) + mx, l0y + (j >> 2) + my);
218  }
219  } else { // descend to 2x2 sub-sub-blocks
220  for (j = 0; j < 4; j++) {
221  l1x = l0x + (j & 1) * 2;
222  l1y = l0y + (j & 2);
223  kmvc_getbit(bb, &ctx->g, res);
224  if (!res) {
225  kmvc_getbit(bb, &ctx->g, res);
226  if (!res) { // fill whole 2x2 block
227  val = bytestream2_get_byte(&ctx->g);
228  BLK(ctx->cur, l1x, l1y) = val;
229  BLK(ctx->cur, l1x + 1, l1y) = val;
230  BLK(ctx->cur, l1x, l1y + 1) = val;
231  BLK(ctx->cur, l1x + 1, l1y + 1) = val;
232  } else { // copy block
233  val = bytestream2_get_byte(&ctx->g);
234  mx = (val & 0xF) - 8;
235  my = (val >> 4) - 8;
236  if ((l1x+mx) + 320*(l1y+my) < 0 || (l1x+mx) + 320*(l1y+my) > 320*199 - 2) {
237  av_log(ctx->avctx, AV_LOG_ERROR, "Invalid MV\n");
238  return AVERROR_INVALIDDATA;
239  }
240  BLK(ctx->cur, l1x, l1y) = BLK(ctx->prev, l1x + mx, l1y + my);
241  BLK(ctx->cur, l1x + 1, l1y) =
242  BLK(ctx->prev, l1x + 1 + mx, l1y + my);
243  BLK(ctx->cur, l1x, l1y + 1) =
244  BLK(ctx->prev, l1x + mx, l1y + 1 + my);
245  BLK(ctx->cur, l1x + 1, l1y + 1) =
246  BLK(ctx->prev, l1x + 1 + mx, l1y + 1 + my);
247  }
248  } else { // read values for block
249  BLK(ctx->cur, l1x, l1y) = bytestream2_get_byte(&ctx->g);
250  BLK(ctx->cur, l1x + 1, l1y) = bytestream2_get_byte(&ctx->g);
251  BLK(ctx->cur, l1x, l1y + 1) = bytestream2_get_byte(&ctx->g);
252  BLK(ctx->cur, l1x + 1, l1y + 1) = bytestream2_get_byte(&ctx->g);
253  }
254  }
255  }
256  }
257  }
258  }
259 
260  return 0;
261 }
262 
263 static int decode_frame(AVCodecContext * avctx, void *data, int *got_frame,
264  AVPacket *avpkt)
265 {
266  KmvcContext *const ctx = avctx->priv_data;
267  AVFrame *frame = data;
268  uint8_t *out, *src;
269  int i, ret;
270  int header;
271  int blocksize;
272 
273  bytestream2_init(&ctx->g, avpkt->data, avpkt->size);
274 
275  if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
276  return ret;
277 
278  frame->palette_has_changed = ff_copy_palette(ctx->pal, avpkt, avctx);
279 
280  header = bytestream2_get_byte(&ctx->g);
281 
282  /* blocksize 127 is really palette change event */
283  if (bytestream2_peek_byte(&ctx->g) == 127) {
284  bytestream2_skip(&ctx->g, 3);
285  for (i = 0; i < 127; i++) {
286  ctx->pal[i + (header & 0x81)] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g);
287  bytestream2_skip(&ctx->g, 1);
288  }
289  bytestream2_seek(&ctx->g, -127 * 4 - 3, SEEK_CUR);
290  }
291 
292  if (header & KMVC_KEYFRAME) {
293  frame->key_frame = 1;
294  frame->pict_type = AV_PICTURE_TYPE_I;
295  } else {
296  frame->key_frame = 0;
297  frame->pict_type = AV_PICTURE_TYPE_P;
298  }
299 
300  if (header & KMVC_PALETTE) {
301  frame->palette_has_changed = 1;
302  // palette starts from index 1 and has 127 entries
303  for (i = 1; i <= ctx->palsize; i++) {
304  ctx->pal[i] = 0xFFU << 24 | bytestream2_get_be24(&ctx->g);
305  }
306  }
307 
308  if (ctx->setpal) {
309  ctx->setpal = 0;
310  frame->palette_has_changed = 1;
311  }
312 
313  /* make the palette available on the way out */
314  memcpy(frame->data[1], ctx->pal, 1024);
315 
316  blocksize = bytestream2_get_byte(&ctx->g);
317 
318  if (blocksize != 8 && blocksize != 127) {
319  av_log(avctx, AV_LOG_ERROR, "Block size = %i\n", blocksize);
320  return AVERROR_INVALIDDATA;
321  }
322  memset(ctx->cur, 0, 320 * 200);
323  switch (header & KMVC_METHOD) {
324  case 0:
325  case 1: // used in palette changed event
326  memcpy(ctx->cur, ctx->prev, 320 * 200);
327  break;
328  case 3:
329  kmvc_decode_intra_8x8(ctx, avctx->width, avctx->height);
330  break;
331  case 4:
332  kmvc_decode_inter_8x8(ctx, avctx->width, avctx->height);
333  break;
334  default:
335  av_log(avctx, AV_LOG_ERROR, "Unknown compression method %i\n", header & KMVC_METHOD);
336  return AVERROR_INVALIDDATA;
337  }
338 
339  out = frame->data[0];
340  src = ctx->cur;
341  for (i = 0; i < avctx->height; i++) {
342  memcpy(out, src, avctx->width);
343  src += 320;
344  out += frame->linesize[0];
345  }
346 
347  /* flip buffers */
348  FFSWAP(uint8_t *, ctx->cur, ctx->prev);
349 
350  *got_frame = 1;
351 
352  /* always report that the buffer was completely consumed */
353  return avpkt->size;
354 }
355 
356 
357 
358 /*
359  * Init kmvc decoder
360  */
362 {
363  KmvcContext *const c = avctx->priv_data;
364  int i;
365 
366  c->avctx = avctx;
367 
368  if (avctx->width > 320 || avctx->height > 200) {
369  av_log(avctx, AV_LOG_ERROR, "KMVC supports frames <= 320x200\n");
370  return AVERROR(EINVAL);
371  }
372 
373  c->cur = c->frm0;
374  c->prev = c->frm1;
375 
376  for (i = 0; i < 256; i++) {
377  c->pal[i] = 0xFFU << 24 | i * 0x10101;
378  }
379 
380  if (avctx->extradata_size < 12) {
381  av_log(avctx, AV_LOG_WARNING,
382  "Extradata missing, decoding may not work properly...\n");
383  c->palsize = 127;
384  } else {
385  c->palsize = AV_RL16(avctx->extradata + 10);
386  if (c->palsize >= (unsigned)MAX_PALSIZE) {
387  c->palsize = 127;
388  av_log(avctx, AV_LOG_ERROR, "KMVC palette too large\n");
389  return AVERROR_INVALIDDATA;
390  }
391  }
392 
393  if (avctx->extradata_size == 1036) { // palette in extradata
394  uint8_t *src = avctx->extradata + 12;
395  for (i = 0; i < 256; i++) {
396  c->pal[i] = AV_RL32(src);
397  src += 4;
398  }
399  c->setpal = 1;
400  }
401 
402  avctx->pix_fmt = AV_PIX_FMT_PAL8;
403 
404  return 0;
405 }
406 
408  .name = "kmvc",
409  .long_name = NULL_IF_CONFIG_SMALL("Karl Morton's video codec"),
410  .type = AVMEDIA_TYPE_VIDEO,
411  .id = AV_CODEC_ID_KMVC,
412  .priv_data_size = sizeof(KmvcContext),
413  .init = decode_init,
414  .decode = decode_frame,
415  .capabilities = AV_CODEC_CAP_DR1,
416 };
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define MAX_PALSIZE
Definition: kmvc.c:39
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
int ff_copy_palette(void *dst, const AVPacket *src, void *logctx)
Check whether the side-data of src contains a palette of size AVPALETTE_SIZE; if so, copy it to dst and return 1; else return 0.
Definition: decode.c:2095
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
GetByteContext g
Definition: kmvc.c:47
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:31
int size
Definition: packet.h:370
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:746
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
#define KMVC_PALETTE
Definition: kmvc.c:37
static int kmvc_decode_inter_8x8(KmvcContext *ctx, int w, int h)
Definition: kmvc.c:163
AVCodec.
Definition: codec.h:197
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_RL16
Definition: bytestream.h:91
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
Definition: decode_audio.c:71
#define BLK(data, x, y)
Definition: kmvc.c:60
uint8_t
#define av_cold
Definition: attributes.h:88
8 bits with AV_PIX_FMT_RGB32 palette
Definition: pixfmt.h:77
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:637
uint8_t * data
Definition: packet.h:369
AVCodecContext * avctx
Definition: kmvc.c:45
static const uint8_t header[24]
Definition: sdr2.c:67
#define av_log(a,...)
static av_always_inline int bytestream2_get_bytes_left(GetByteContext *g)
Definition: bytestream.h:158
#define U(x)
Definition: vp56_arith.h:37
#define src
Definition: vp8dsp.c:255
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
int palsize
Definition: kmvc.c:50
static int kmvc_decode_intra_8x8(KmvcContext *ctx, int w, int h)
Definition: kmvc.c:74
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:117
int bitbuf
Definition: kmvc.c:57
uint32_t BitBuf
Definition: put_bits.h:44
const char * name
Name of the codec implementation.
Definition: codec.h:204
#define kmvc_init_getbits(bb, g)
Definition: kmvc.c:62
int bits
Definition: kmvc.c:56
uint8_t frm1[320 *200]
Definition: kmvc.c:52
AVCodec ff_kmvc_decoder
Definition: kmvc.c:407
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:401
int width
picture width / height.
Definition: avcodec.h:709
#define kmvc_getbit(bb, g, res)
Definition: kmvc.c:64
uint8_t frm0[320 *200]
Definition: kmvc.c:52
uint8_t w
Definition: llviddspenc.c:39
static av_cold int decode_init(AVCodecContext *avctx)
Definition: kmvc.c:361
AVFormatContext * ctx
Definition: movenc.c:48
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: kmvc.c:263
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
#define KMVC_METHOD
Definition: kmvc.c:38
int setpal
Definition: kmvc.c:49
Libavcodec external API header.
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:349
main external API structure.
Definition: avcodec.h:536
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
Definition: decode.c:1893
int extradata_size
Definition: avcodec.h:638
Definition: kmvc.c:55
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:475
uint8_t * prev
Definition: kmvc.c:48
uint8_t * cur
Definition: kmvc.c:48
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:332
common internal api header.
common internal and external API header
#define KMVC_KEYFRAME
Definition: kmvc.c:36
void * priv_data
Definition: avcodec.h:563
int key_frame
1 -> keyframe, 0-> not
Definition: frame.h:396
static av_always_inline int bytestream2_seek(GetByteContext *g, int offset, int whence)
Definition: bytestream.h:212
FILE * out
Definition: movenc.c:54
#define FFSWAP(type, a, b)
Definition: common.h:108
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
uint32_t pal[MAX_PALSIZE]
Definition: kmvc.c:51
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_RL32
Definition: bytestream.h:91
static double val(void *priv, double ch)
Definition: aeval.c:76
This structure stores compressed data.
Definition: packet.h:346
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() or get_encode_buffer() for allocating buffers and supports custom allocators...
Definition: codec.h:52
int i
Definition: input.c:407
Predicted.
Definition: avutil.h:275