| Line | Branch | Exec | Source |
|---|---|---|---|
| 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 | 2 | static uint8_t *encode_frames(const AVCodec *enc, int width, int height, | |
| 54 | int n_frames, size_t *out_size) | ||
| 55 | { | ||
| 56 | 2 | AVCodecContext *enc_ctx = NULL; | |
| 57 | 2 | AVFrame *frame = NULL; | |
| 58 | 2 | AVPacket *pkt = NULL; | |
| 59 | 2 | uint8_t *buf = NULL, *tmp; | |
| 60 | 2 | 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 | 2 | *out_size = 0; | |
| 68 | |||
| 69 | 2 | enc_ctx = avcodec_alloc_context3(enc); | |
| 70 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!enc_ctx) |
| 71 | ✗ | return NULL; | |
| 72 | |||
| 73 | /* use first supported pixel format, fall back to yuv420p */ | ||
| 74 | 2 | ret = avcodec_get_supported_config(enc_ctx, enc, AV_CODEC_CONFIG_PIX_FORMAT, | |
| 75 | 0, (const void **)&pix_fmts, &num_pix_fmts); | ||
| 76 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | enc_ctx->pix_fmt = (ret >= 0 && num_pix_fmts > 0) ? pix_fmts[0] |
| 77 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | : AV_PIX_FMT_YUV420P; |
| 78 | 2 | enc_ctx->width = width; | |
| 79 | 2 | enc_ctx->height = height; | |
| 80 | 2 | enc_ctx->time_base = (AVRational){ 1, 25 }; | |
| 81 | |||
| 82 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (avcodec_open2(enc_ctx, enc, NULL) < 0) |
| 83 | ✗ | goto fail; | |
| 84 | |||
| 85 | 2 | desc = av_pix_fmt_desc_get(enc_ctx->pix_fmt); | |
| 86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!desc) |
| 87 | ✗ | goto fail; | |
| 88 | 2 | chroma_h = AV_CEIL_RSHIFT(height, desc->log2_chroma_h); | |
| 89 | |||
| 90 | 2 | frame = av_frame_alloc(); | |
| 91 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!frame) |
| 92 | ✗ | goto fail; | |
| 93 | |||
| 94 | 2 | frame->format = enc_ctx->pix_fmt; | |
| 95 | 2 | frame->width = width; | |
| 96 | 2 | frame->height = height; | |
| 97 | |||
| 98 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if (av_frame_get_buffer(frame, 0) < 0) |
| 99 | ✗ | goto fail; | |
| 100 | |||
| 101 | 2 | pkt = av_packet_alloc(); | |
| 102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!pkt) |
| 103 | ✗ | goto fail; | |
| 104 | |||
| 105 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int i = 0; i < n_frames; i++) { |
| 106 | 4 | frame->pts = i; | |
| 107 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (av_frame_make_writable(frame) < 0) |
| 108 | ✗ | goto fail; | |
| 109 | /* fill with flat color so encoder produces deterministic output */ | ||
| 110 | 4 | memset(frame->data[0], 128, (size_t)frame->linesize[0] * height); | |
| 111 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (frame->data[1]) |
| 112 | 4 | memset(frame->data[1], 64, (size_t)frame->linesize[1] * chroma_h); | |
| 113 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (frame->data[2]) |
| 114 | 4 | memset(frame->data[2], 64, (size_t)frame->linesize[2] * chroma_h); | |
| 115 | |||
| 116 | 4 | ret = avcodec_send_frame(enc_ctx, frame); | |
| 117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (ret < 0) |
| 118 | ✗ | goto fail; | |
| 119 | |||
| 120 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | while (ret >= 0) { |
| 121 | 8 | ret = avcodec_receive_packet(enc_ctx, pkt); | |
| 122 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (ret == AVERROR(EAGAIN)) |
| 123 | 4 | break; | |
| 124 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (ret < 0) |
| 125 | ✗ | goto fail; | |
| 126 | |||
| 127 | 4 | tmp = av_realloc(buf, buf_size + pkt->size + AV_INPUT_BUFFER_PADDING_SIZE); | |
| 128 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!tmp) { |
| 129 | ✗ | av_packet_unref(pkt); | |
| 130 | ✗ | goto fail; | |
| 131 | } | ||
| 132 | 4 | buf = tmp; | |
| 133 | 4 | memcpy(buf + buf_size, pkt->data, pkt->size); | |
| 134 | 4 | buf_size += pkt->size; | |
| 135 | 4 | av_packet_unref(pkt); | |
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /* flush encoder */ | ||
| 140 | 2 | ret = avcodec_send_frame(enc_ctx, NULL); | |
| 141 |
1/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | if (ret < 0 && ret != AVERROR_EOF) |
| 142 | ✗ | goto fail; | |
| 143 | while (1) { | ||
| 144 | 2 | ret = avcodec_receive_packet(enc_ctx, pkt); | |
| 145 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2 | 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) { | |
| 151 | ✗ | av_packet_unref(pkt); | |
| 152 | ✗ | goto fail; | |
| 153 | } | ||
| 154 | ✗ | buf = tmp; | |
| 155 | ✗ | memcpy(buf + buf_size, pkt->data, pkt->size); | |
| 156 | ✗ | buf_size += pkt->size; | |
| 157 | ✗ | av_packet_unref(pkt); | |
| 158 | } | ||
| 159 | |||
| 160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!buf) |
| 161 | ✗ | goto fail; | |
| 162 | 2 | memset(buf + buf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
| 163 | 2 | *out_size = buf_size; | |
| 164 | 2 | av_frame_free(&frame); | |
| 165 | 2 | av_packet_free(&pkt); | |
| 166 | 2 | avcodec_free_context(&enc_ctx); | |
| 167 | 2 | return buf; | |
| 168 | |||
| 169 | ✗ | fail: | |
| 170 | ✗ | av_free(buf); | |
| 171 | ✗ | av_frame_free(&frame); | |
| 172 | ✗ | av_packet_free(&pkt); | |
| 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 | 10 | static void print_parse_result(const char *label, | |
| 179 | const uint8_t *out, int out_size) | ||
| 180 | { | ||
| 181 | 10 | printf("%s: out_size=%d", label, out_size); | |
| 182 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
10 | if (out && out_size > 0) { |
| 183 | 8 | int n = out_size < 4 ? out_size : 4; | |
| 184 | int k; | ||
| 185 | 8 | printf(" first="); | |
| 186 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
|
40 | for (k = 0; k < n; k++) |
| 187 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
|
32 | printf(k ? " %02x" : "%02x", out[k]); |
| 188 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | if (out_size > 4) { |
| 189 | 8 | printf(" last="); | |
| 190 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 8 times.
|
40 | for (k = out_size - 4; k < out_size; k++) |
| 191 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
|
32 | printf(k > out_size - 4 ? " %02x" : "%02x", out[k]); |
| 192 | } | ||
| 193 | } | ||
| 194 | 10 | printf("\n"); | |
| 195 | 10 | } | |
| 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 | 2 | static int parse_once(AVCodecContext *avctx, enum AVCodecID codec_id, | |
| 203 | const char *label, | ||
| 204 | const uint8_t *buf, int buf_size) | ||
| 205 | { | ||
| 206 | 2 | AVCodecParserContext *parser = av_parser_init(codec_id); | |
| 207 | uint8_t *out; | ||
| 208 | int out_size, ret; | ||
| 209 | |||
| 210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!parser) |
| 211 | ✗ | return AVERROR(ENOSYS); | |
| 212 | 2 | ret = av_parser_parse2(parser, avctx, &out, &out_size, | |
| 213 | buf, buf_size, | ||
| 214 | AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1); | ||
| 215 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | print_parse_result(label, out, ret < 0 ? 0 : out_size); |
| 216 | 2 | av_parser_close(parser); | |
| 217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | 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 | */ | ||
| 226 | 4 | static int parse_stream(AVCodecContext *avctx, enum AVCodecID codec_id, | |
| 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 | { | ||
| 231 | 4 | AVCodecParserContext *parser = av_parser_init(codec_id); | |
| 232 | 4 | const uint8_t *p = buf; | |
| 233 | 4 | int remaining = buf_size; | |
| 234 | 4 | int n = 0; | |
| 235 | uint8_t *out; | ||
| 236 | int out_size, consumed; | ||
| 237 | |||
| 238 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!parser) |
| 239 | ✗ | return AVERROR(ENOSYS); | |
| 240 | |||
| 241 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (chunk_size <= 0) |
| 242 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | chunk_size = buf_size ? buf_size : 1; |
| 243 | |||
| 244 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
|
14 | while (remaining > 0) { |
| 245 | 10 | int feed = remaining < chunk_size ? remaining : chunk_size; | |
| 246 | 10 | consumed = av_parser_parse2(parser, avctx, &out, &out_size, | |
| 247 | p, feed, | ||
| 248 | AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1); | ||
| 249 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (consumed < 0) { |
| 250 | ✗ | av_parser_close(parser); | |
| 251 | ✗ | return consumed; | |
| 252 | } | ||
| 253 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | if (out_size > 0) { |
| 254 | char label[64]; | ||
| 255 | 4 | snprintf(label, sizeof(label), "%s[%d]", tag, n++); | |
| 256 | 4 | print_parse_result(label, out, out_size); | |
| 257 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (all_out) { |
| 258 | 4 | uint8_t *tmp = av_realloc(*all_out, *all_size + out_size); | |
| 259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!tmp) { |
| 260 | ✗ | av_parser_close(parser); | |
| 261 | ✗ | return AVERROR(ENOMEM); | |
| 262 | } | ||
| 263 | 4 | memcpy(tmp + *all_size, out, out_size); | |
| 264 | 4 | *all_out = tmp; | |
| 265 | 4 | *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 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | p += consumed > 0 ? consumed : feed; |
| 271 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | remaining -= consumed > 0 ? consumed : feed; |
| 272 | } | ||
| 273 | |||
| 274 | /* flush any frame the parser held waiting for a next-frame start code */ | ||
| 275 | 4 | consumed = av_parser_parse2(parser, avctx, &out, &out_size, | |
| 276 | NULL, 0, | ||
| 277 | AV_NOPTS_VALUE, AV_NOPTS_VALUE, -1); | ||
| 278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (consumed < 0) { |
| 279 | ✗ | av_parser_close(parser); | |
| 280 | ✗ | return consumed; | |
| 281 | } | ||
| 282 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (out_size > 0) { |
| 283 | char label[64]; | ||
| 284 | 4 | snprintf(label, sizeof(label), "%s[%d]", tag, n++); | |
| 285 | 4 | print_parse_result(label, out, out_size); | |
| 286 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (all_out) { |
| 287 | 4 | uint8_t *tmp = av_realloc(*all_out, *all_size + out_size); | |
| 288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!tmp) { |
| 289 | ✗ | av_parser_close(parser); | |
| 290 | ✗ | return AVERROR(ENOMEM); | |
| 291 | } | ||
| 292 | 4 | memcpy(tmp + *all_size, out, out_size); | |
| 293 | 4 | *all_out = tmp; | |
| 294 | 4 | *all_size += out_size; | |
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 298 | 4 | av_parser_close(parser); | |
| 299 | 4 | return n; | |
| 300 | } | ||
| 301 | |||
| 302 | 2 | int main(int argc, char **argv) | |
| 303 | { | ||
| 304 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | const char *codec_name = argc > 1 ? argv[1] : "h261"; |
| 305 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | int width = argc > 2 ? atoi(argv[2]) : 176; |
| 306 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | int height = argc > 3 ? atoi(argv[3]) : 144; |
| 307 | 2 | AVCodecContext *avctx = NULL; | |
| 308 | AVCodecParserContext *parser; | ||
| 309 | 2 | uint8_t *encoded = NULL; | |
| 310 | size_t encoded_size; | ||
| 311 | enum AVCodecID codec_id; | ||
| 312 | const AVCodec *enc; | ||
| 313 | 2 | uint8_t *bulk_data = NULL, *split_data = NULL; | |
| 314 | 2 | size_t bulk_sz = 0, split_sz = 0; | |
| 315 | int n, ret; | ||
| 316 | |||
| 317 | 2 | av_log_set_level(AV_LOG_ERROR); | |
| 318 | |||
| 319 | 2 | enc = avcodec_find_encoder_by_name(codec_name); | |
| 320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!enc) { |
| 321 | ✗ | av_log(NULL, AV_LOG_ERROR, "encoder '%s' not found\n", codec_name); | |
| 322 | ✗ | return 1; | |
| 323 | } | ||
| 324 | 2 | codec_id = enc->id; | |
| 325 | |||
| 326 | /* verify parser is available before running tests */ | ||
| 327 | 2 | parser = av_parser_init(codec_id); | |
| 328 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!parser) { |
| 329 | ✗ | av_log(NULL, AV_LOG_ERROR, "parser for '%s' not available\n", codec_name); | |
| 330 | ✗ | return 1; | |
| 331 | } | ||
| 332 | 2 | av_parser_close(parser); | |
| 333 | |||
| 334 | 2 | avctx = avcodec_alloc_context3(NULL); | |
| 335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!avctx) |
| 336 | ✗ | return 1; | |
| 337 | 2 | avctx->codec_id = codec_id; | |
| 338 | |||
| 339 | /* encode two real frames to use as parser input */ | ||
| 340 | 2 | encoded = encode_frames(enc, width, height, 2, &encoded_size); | |
| 341 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | 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 | 2 | ret = parse_once(avctx, codec_id, "garbage", garbage, (int)sizeof(garbage)); | |
| 349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | 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 | 2 | n = parse_stream(avctx, codec_id, "bulk", encoded, (int)encoded_size, 0, | |
| 357 | &bulk_data, &bulk_sz); | ||
| 358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | 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 | 2 | n = parse_stream(avctx, codec_id, "split", encoded, (int)encoded_size, | |
| 366 | 2 | (int)encoded_size / 2, &split_data, &split_sz); | |
| 367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (n != 2) { |
| 368 | ✗ | av_log(NULL, AV_LOG_ERROR, "split test failed: got %d frames\n", n); | |
| 369 | ✗ | goto fail; | |
| 370 | } | ||
| 371 | |||
| 372 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | 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 | 2 | av_free(bulk_data); | |
| 378 | 2 | av_free(split_data); | |
| 379 | 2 | av_free(encoded); | |
| 380 | 2 | avcodec_free_context(&avctx); | |
| 381 | 2 | 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 | } | ||
| 390 |