FFmpeg
api-enc-parser-test.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2026 Soham Kute
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 /*
24  * Encoder + parser API test.
25  * Usage: api-enc-parser-test [codec_name [width height]]
26  * Defaults: h261, 176, 144
27  *
28  * Encodes two frames with the named encoder, concatenates the packets,
29  * and feeds the result to the matching parser to verify frame boundary
30  * detection. For each non-empty output the size and up to four bytes
31  * at the start and end are printed for comparison against a reference file.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #include "libavcodec/avcodec.h"
39 #include "libavutil/log.h"
40 #include "libavutil/mem.h"
41 #include "libavutil/pixdesc.h"
42 
43 /* Garbage with no PSC - parser must return out_size == 0 */
44 static const uint8_t garbage[] = {
45  0xff, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78,
46 };
47 
48 /*
49  * Encode n_frames of video at width x height using enc.
50  * Returns concatenated raw bitstream; caller must av_free() it.
51  * Returns NULL on error.
52  */
53 static uint8_t *encode_frames(const AVCodec *enc, int width, int height,
54  int n_frames, size_t *out_size)
55 {
56  AVCodecContext *enc_ctx = NULL;
57  AVFrame *frame = NULL;
58  AVPacket *pkt = NULL;
59  uint8_t *buf = NULL, *tmp;
60  size_t buf_size = 0;
61  const enum AVPixelFormat *pix_fmts;
62  const AVPixFmtDescriptor *desc;
63  int num_pix_fmts;
64  int chroma_h;
65  int ret;
66 
67  *out_size = 0;
68 
69  enc_ctx = avcodec_alloc_context3(enc);
70  if (!enc_ctx)
71  return NULL;
72 
73  /* use first supported pixel format, fall back to yuv420p */
75  0, (const void **)&pix_fmts, &num_pix_fmts);
76  enc_ctx->pix_fmt = (ret >= 0 && num_pix_fmts > 0) ? pix_fmts[0]
78  enc_ctx->width = width;
79  enc_ctx->height = height;
80  enc_ctx->time_base = (AVRational){ 1, 25 };
81 
82  if (avcodec_open2(enc_ctx, enc, NULL) < 0)
83  goto fail;
84 
85  desc = av_pix_fmt_desc_get(enc_ctx->pix_fmt);
86  if (!desc)
87  goto fail;
88  chroma_h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h);
89 
91  if (!frame)
92  goto fail;
93 
94  frame->format = enc_ctx->pix_fmt;
95  frame->width = width;
96  frame->height = height;
97 
98  if (av_frame_get_buffer(frame, 0) < 0)
99  goto fail;
100 
101  pkt = av_packet_alloc();
102  if (!pkt)
103  goto fail;
104 
105  for (int i = 0; i < n_frames; i++) {
106  frame->pts = i;
107  if (av_frame_make_writable(frame) < 0)
108  goto fail;
109  /* fill with flat color so encoder produces deterministic output */
110  memset(frame->data[0], 128, (size_t)frame->linesize[0] * height);
111  if (frame->data[1])
112  memset(frame->data[1], 64, (size_t)frame->linesize[1] * chroma_h);
113  if (frame->data[2])
114  memset(frame->data[2], 64, (size_t)frame->linesize[2] * chroma_h);
115 
116  ret = avcodec_send_frame(enc_ctx, frame);
117  if (ret < 0)
118  goto fail;
119 
120  while (ret >= 0) {
121  ret = avcodec_receive_packet(enc_ctx, pkt);
122  if (ret == AVERROR(EAGAIN))
123  break;
124  if (ret < 0)
125  goto fail;
126 
127  tmp = av_realloc(buf, buf_size + pkt->size + AV_INPUT_BUFFER_PADDING_SIZE);
128  if (!tmp) {
130  goto fail;
131  }
132  buf = tmp;
133  memcpy(buf + buf_size, pkt->data, pkt->size);
134  buf_size += pkt->size;
136  }
137  }
138 
139  /* flush encoder */
140  ret = avcodec_send_frame(enc_ctx, NULL);
141  if (ret < 0 && ret != AVERROR_EOF)
142  goto fail;
143  while (1) {
144  ret = avcodec_receive_packet(enc_ctx, pkt);
145  if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
146  break;
147  if (ret < 0)
148  goto fail;
149  tmp = av_realloc(buf, buf_size + pkt->size + AV_INPUT_BUFFER_PADDING_SIZE);
150  if (!tmp) {
152  goto fail;
153  }
154  buf = tmp;
155  memcpy(buf + buf_size, pkt->data, pkt->size);
156  buf_size += pkt->size;
158  }
159 
160  if (!buf)
161  goto fail;
162  memset(buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
163  *out_size = buf_size;
166  avcodec_free_context(&enc_ctx);
167  return buf;
168 
169 fail:
170  av_free(buf);
173  avcodec_free_context(&enc_ctx);
174  return NULL;
175 }
176 
177 /* Print label, out_size, and first/last 4 bytes of out when non-empty. */
178 static void print_parse_result(const char *label,
179  const uint8_t *out, int out_size)
180 {
181  printf("%s: out_size=%d", label, out_size);
182  if (out && out_size > 0) {
183  int n = out_size < 4 ? out_size : 4;
184  int k;
185  printf(" first=");
186  for (k = 0; k < n; k++)
187  printf(k ? " %02x" : "%02x", out[k]);
188  if (out_size > 4) {
189  printf(" last=");
190  for (k = out_size - 4; k < out_size; k++)
191  printf(k > out_size - 4 ? " %02x" : "%02x", out[k]);
192  }
193  }
194  printf("\n");
195 }
196 
197 /*
198  * Single parse call on buf — prints the result with label.
199  * Returns out_size on success, negative AVERROR on error.
200  * No flush; used to verify the parser does not emit output for a given input.
201  */
202 static int parse_once(AVCodecContext *avctx, enum AVCodecID codec_id,
203  const char *label,
204  const uint8_t *buf, int buf_size)
205 {
207  uint8_t *out;
208  int out_size, ret;
209 
210  if (!parser)
211  return AVERROR(ENOSYS);
212  ret = av_parser_parse2(parser, avctx, &out, &out_size,
213  buf, buf_size,
215  print_parse_result(label, out, ret < 0 ? 0 : out_size);
216  av_parser_close(parser);
217  return ret < 0 ? ret : out_size;
218 }
219 
220 /*
221  * Feed buf through a fresh parser in chunks of chunk_size bytes.
222  * chunk_size=0 feeds all data in one call.
223  * Prints each emitted frame as "tag[N]".
224  * Returns frame count (>=0) or negative AVERROR on error.
225  */
227  const char *tag,
228  const uint8_t *buf, int buf_size, int chunk_size,
229  uint8_t **all_out, size_t *all_size)
230 {
232  const uint8_t *p = buf;
233  int remaining = buf_size;
234  int n = 0;
235  uint8_t *out;
236  int out_size, consumed;
237 
238  if (!parser)
239  return AVERROR(ENOSYS);
240 
241  if (chunk_size <= 0)
242  chunk_size = buf_size ? buf_size : 1;
243 
244  while (remaining > 0) {
245  int feed = remaining < chunk_size ? remaining : chunk_size;
246  consumed = av_parser_parse2(parser, avctx, &out, &out_size,
247  p, feed,
249  if (consumed < 0) {
250  av_parser_close(parser);
251  return consumed;
252  }
253  if (out_size > 0) {
254  char label[64];
255  snprintf(label, sizeof(label), "%s[%d]", tag, n++);
257  if (all_out) {
258  uint8_t *tmp = av_realloc(*all_out, *all_size + out_size);
259  if (!tmp) {
260  av_parser_close(parser);
261  return AVERROR(ENOMEM);
262  }
263  memcpy(tmp + *all_size, out, out_size);
264  *all_out = tmp;
265  *all_size += out_size;
266  }
267  }
268  /* advance by consumed bytes; if parser consumed nothing, skip the
269  * fed chunk to avoid an infinite loop */
270  p += consumed > 0 ? consumed : feed;
271  remaining -= consumed > 0 ? consumed : feed;
272  }
273 
274  /* flush any frame the parser held waiting for a next-frame start code */
275  consumed = av_parser_parse2(parser, avctx, &out, &out_size,
276  NULL, 0,
278  if (consumed < 0) {
279  av_parser_close(parser);
280  return consumed;
281  }
282  if (out_size > 0) {
283  char label[64];
284  snprintf(label, sizeof(label), "%s[%d]", tag, n++);
286  if (all_out) {
287  uint8_t *tmp = av_realloc(*all_out, *all_size + out_size);
288  if (!tmp) {
289  av_parser_close(parser);
290  return AVERROR(ENOMEM);
291  }
292  memcpy(tmp + *all_size, out, out_size);
293  *all_out = tmp;
294  *all_size += out_size;
295  }
296  }
297 
298  av_parser_close(parser);
299  return n;
300 }
301 
302 int main(int argc, char **argv)
303 {
304  const char *codec_name = argc > 1 ? argv[1] : "h261";
305  int width = argc > 2 ? atoi(argv[2]) : 176;
306  int height = argc > 3 ? atoi(argv[3]) : 144;
307  AVCodecContext *avctx = NULL;
308  AVCodecParserContext *parser;
309  uint8_t *encoded = NULL;
310  size_t encoded_size;
311  enum AVCodecID codec_id;
312  const AVCodec *enc;
313  uint8_t *bulk_data = NULL, *split_data = NULL;
314  size_t bulk_sz = 0, split_sz = 0;
315  int n, ret;
316 
318 
319  enc = avcodec_find_encoder_by_name(codec_name);
320  if (!enc) {
321  av_log(NULL, AV_LOG_ERROR, "encoder '%s' not found\n", codec_name);
322  return 1;
323  }
324  codec_id = enc->id;
325 
326  /* verify parser is available before running tests */
327  parser = av_parser_init(codec_id);
328  if (!parser) {
329  av_log(NULL, AV_LOG_ERROR, "parser for '%s' not available\n", codec_name);
330  return 1;
331  }
332  av_parser_close(parser);
333 
334  avctx = avcodec_alloc_context3(NULL);
335  if (!avctx)
336  return 1;
337  avctx->codec_id = codec_id;
338 
339  /* encode two real frames to use as parser input */
340  encoded = encode_frames(enc, width, height, 2, &encoded_size);
341  if (!encoded || encoded_size == 0) {
342  av_log(NULL, AV_LOG_ERROR, "encoder '%s' failed\n", codec_name);
343  avcodec_free_context(&avctx);
344  return 1;
345  }
346 
347  /* test 1: single parse call on garbage — no PSC means out_size must be 0 */
348  ret = parse_once(avctx, codec_id, "garbage", garbage, (int)sizeof(garbage));
349  if (ret != 0) {
350  av_log(NULL, AV_LOG_ERROR, "garbage test failed\n");
351  goto fail;
352  }
353 
354  /* test 2: two real encoded frames fed all at once — parser must split
355  * them and emit exactly 2 frames */
356  n = parse_stream(avctx, codec_id, "bulk", encoded, (int)encoded_size, 0,
357  &bulk_data, &bulk_sz);
358  if (n != 2) {
359  av_log(NULL, AV_LOG_ERROR, "bulk test failed: got %d frames\n", n);
360  goto fail;
361  }
362 
363  /* test 3: same two frames split mid-stream — verify the parser handles
364  * partial input and still emits exactly 2 frames, with identical bytes */
365  n = parse_stream(avctx, codec_id, "split", encoded, (int)encoded_size,
366  (int)encoded_size / 2, &split_data, &split_sz);
367  if (n != 2) {
368  av_log(NULL, AV_LOG_ERROR, "split test failed: got %d frames\n", n);
369  goto fail;
370  }
371 
372  if (bulk_sz != split_sz || memcmp(bulk_data, split_data, bulk_sz) != 0) {
373  av_log(NULL, AV_LOG_ERROR, "bulk and split outputs differ\n");
374  goto fail;
375  }
376 
377  av_free(bulk_data);
378  av_free(split_data);
379  av_free(encoded);
380  avcodec_free_context(&avctx);
381  return 0;
382 
383 fail:
384  av_free(bulk_data);
385  av_free(split_data);
386  av_free(encoded);
387  avcodec_free_context(&avctx);
388  return 1;
389 }
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:432
AVCodec
AVCodec.
Definition: codec.h:172
AVPixelFormat
AVPixelFormat
Pixel format.
Definition: pixfmt.h:71
avcodec_receive_packet
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Read encoded data from the encoder.
Definition: encode.c:524
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
printf
__device__ int printf(const char *,...)
out
static FILE * out
Definition: movenc.c:55
av_frame_get_buffer
int av_frame_get_buffer(AVFrame *frame, int align)
Allocate new buffer(s) for audio or video data.
Definition: frame.c:206
av_pix_fmt_desc_get
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:3456
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
out_size
static int out_size
Definition: movenc.c:56
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:64
feed
static void feed(AVFilterContext *ctx, int ch, const float *in_samples, float *out_samples, float *in_frame, float *out_dist_frame, float *windowed_frame, float *drc_frame, float *spectrum_buf, float *energy, float *target_gain, float *envelope, float *factors)
Definition: af_adrc.c:275
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:427
av_frame_make_writable
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition: frame.c:552
pixdesc.h
AVPacket::data
uint8_t * data
Definition: packet.h:588
AV_CODEC_CONFIG_PIX_FORMAT
@ AV_CODEC_CONFIG_PIX_FORMAT
AVPixelFormat, terminated by AV_PIX_FMT_NONE.
Definition: avcodec.h:2549
print_parse_result
static void print_parse_result(const char *label, const uint8_t *out, int out_size)
Definition: api-enc-parser-test.c:178
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:74
fail
#define fail()
Definition: checkasm.h:223
parse_stream
static int parse_stream(AVCodecContext *avctx, enum AVCodecID codec_id, const char *tag, const uint8_t *buf, int buf_size, int chunk_size, uint8_t **all_out, size_t *all_size)
Definition: api-enc-parser-test.c:226
av_parser_init
AVCodecParserContext * av_parser_init(int codec_id)
Definition: parser.c:36
encode_frames
static uint8_t * encode_frames(const AVCodec *enc, int width, int height, int n_frames, size_t *out_size)
Definition: api-enc-parser-test.c:53
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:52
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
garbage
static const uint8_t garbage[]
Definition: api-enc-parser-test.c:44
avcodec_alloc_context3
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:149
AV_CEIL_RSHIFT
#define AV_CEIL_RSHIFT(a, b)
Definition: common.h:60
codec_id
enum AVCodecID codec_id
Definition: vaapi_decode.c:410
AV_PIX_FMT_YUV420P
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:73
tmp
static uint8_t tmp[40]
Definition: aes_ctr.c:52
AVCodecContext::codec_id
enum AVCodecID codec_id
Definition: avcodec.h:449
NULL
#define NULL
Definition: coverity.c:32
avcodec_free_context
void avcodec_free_context(AVCodecContext **avctx)
Free the codec context and everything associated with it and write NULL to the provided pointer.
Definition: options.c:164
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
avcodec_open2
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition: avcodec.c:144
main
int main(int argc, char **argv)
Definition: api-enc-parser-test.c:302
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:49
AVCodecContext::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avcodec.h:543
avcodec_get_supported_config
int avcodec_get_supported_config(const AVCodecContext *avctx, const AVCodec *codec, enum AVCodecConfig config, unsigned flags, const void **out, int *out_num)
Retrieve a list of all supported values for a given configuration type.
Definition: avcodec.c:823
AVPacket::size
int size
Definition: packet.h:589
pix_fmts
static enum AVPixelFormat pix_fmts[4][4]
Definition: lcevc_parser.c:75
height
#define height
Definition: dsp.h:89
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:247
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:63
AVCodec::id
enum AVCodecID id
Definition: codec.h:186
av_log_set_level
void av_log_set_level(int level)
Set the log level.
Definition: log.c:477
log.h
AVCodecContext::height
int height
Definition: avcodec.h:600
avcodec_send_frame
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
Supply a raw video or audio frame to the encoder.
Definition: encode.c:491
AVCodecContext::pix_fmt
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition: avcodec.h:639
avcodec.h
AVCodecParserContext
Definition: avcodec.h:2593
tag
uint32_t tag
Definition: movenc.c:2046
ret
ret
Definition: filter_design.txt:187
frame
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
Definition: filter_design.txt:265
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
AVCodecContext
main external API structure.
Definition: avcodec.h:439
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
av_realloc
#define av_realloc(p, s)
Definition: ops_asmgen.c:46
desc
const char * desc
Definition: libsvtav1.c:82
av_parser_parse2
int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)
Parse a packet.
Definition: parser.c:124
mem.h
AVPixFmtDescriptor
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:69
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVPacket
This structure stores compressed data.
Definition: packet.h:565
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:600
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
pkt
static AVPacket * pkt
Definition: demux_decode.c:55
width
#define width
Definition: dsp.h:89
snprintf
#define snprintf
Definition: snprintf.h:34
parse_once
static int parse_once(AVCodecContext *avctx, enum AVCodecID codec_id, const char *label, const uint8_t *buf, int buf_size)
Definition: api-enc-parser-test.c:202
av_parser_close
void av_parser_close(AVCodecParserContext *s)
Definition: parser.c:207
avcodec_find_encoder_by_name
const AVCodec * avcodec_find_encoder_by_name(const char *name)
Find a registered encoder with the specified name.
Definition: allcodecs.c:1071