FFmpeg
Loading...
Searching...
No Matches
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 */
44static 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 */
53static 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;
58 AVPacket *pkt = NULL;
59 uint8_t *buf = NULL, *tmp;
60 size_t buf_size = 0;
61 const enum AVPixelFormat *pix_fmts;
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
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
102 if (!pkt)
103 goto fail;
104
105 for (int i = 0; i < n_frames; i++) {
106 frame->pts = i;
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
169fail:
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. */
178static 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 */
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
302int 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
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
383fail:
384 av_free(bulk_data);
385 av_free(split_data);
386 av_free(encoded);
387 avcodec_free_context(&avctx);
388 return 1;
389}
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
static int parse_once(AVCodecContext *avctx, enum AVCodecID codec_id, const char *label, const uint8_t *buf, int buf_size)
static uint8_t * encode_frames(const AVCodec *enc, int width, int height, int n_frames, size_t *out_size)
static const uint8_t garbage[]
static void print_parse_result(const char *label, const uint8_t *out, int out_size)
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)
static FILE * out
static int out_size
Libavcodec external API header.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
static AVPacket * pkt
static AVFrame * frame
int main
Definition dovi_rpuenc.c:38
#define fail
Definition test.h:479
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
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition options.c:149
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition codec_id.h:47
const AVCodec * avcodec_find_encoder_by_name(const char *name)
Find a registered encoder with the specified name.
Definition allcodecs.c:1013
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
int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
Read encoded data from the encoder.
Definition encode.c:578
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition defs.h:40
int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame)
Supply a raw video or audio frame to the encoder.
Definition encode.c:545
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:818
@ AV_CODEC_CONFIG_PIX_FORMAT
AVPixelFormat, terminated by AV_PIX_FMT_NONE.
Definition avcodec.h:2573
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition packet.c:74
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition packet.c:434
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition packet.c:63
AVCodecParserContext * av_parser_init(enum AVCodecID codec_id)
Definition parser.c:35
void av_parser_close(AVCodecParserContext *s)
Definition parser.c:203
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:120
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
int av_frame_get_buffer(AVFrame *frame, int align)
Allocate new buffer(s) for audio or video data.
Definition frame.c:206
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition frame.c:52
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
Definition frame.c:552
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
void av_log_set_level(int level)
Set the log level.
Definition log.c:476
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
static enum AVPixelFormat pix_fmts[]
Definition libkvazaar.c:296
const char * desc
Definition libsvtav1.c:83
Memory handling functions.
uint32_t tag
Definition movenc.c:2087
#define av_realloc(p, s)
Definition ops_static.c:54
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
#define snprintf
Definition snprintf.h:34
main external API structure.
Definition avcodec.h:443
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
Definition avcodec.h:643
int width
picture width / height.
Definition avcodec.h:604
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avcodec.h:547
enum AVCodecID codec_id
Definition avcodec.h:453
AVCodec.
Definition codec.h:175
enum AVCodecID id
Definition codec.h:189
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
This structure stores compressed data.
Definition packet.h:580
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
Rational number (pair of numerator and denominator).
Definition rational.h:58
#define av_free(p)
#define av_log(a,...)
static uint8_t tmp[40]
Definition aes_ctr.c:52
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
enum AVCodecID codec_id