| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * copyright (c) 2022 Anton Khirnov <anton@khirnov.net> | ||
| 3 | * | ||
| 4 | * This file is part of FFmpeg. | ||
| 5 | * | ||
| 6 | * FFmpeg is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public | ||
| 8 | * License as published by the Free Software Foundation; either | ||
| 9 | * version 2.1 of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * Lesser General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public | ||
| 17 | * License along with FFmpeg; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | /* A test for AV_CODEC_FLAG_RECON_FRAME | ||
| 22 | * TODO: dump reconstructed frames to disk */ | ||
| 23 | |||
| 24 | #include <stdio.h> | ||
| 25 | #include <stdint.h> | ||
| 26 | #include <stdlib.h> | ||
| 27 | |||
| 28 | #include "decode_simple.h" | ||
| 29 | |||
| 30 | #include "libavutil/adler32.h" | ||
| 31 | #include "libavutil/avassert.h" | ||
| 32 | #include "libavutil/common.h" | ||
| 33 | #include "libavutil/error.h" | ||
| 34 | #include "libavutil/frame.h" | ||
| 35 | #include "libavutil/imgutils.h" | ||
| 36 | #include "libavutil/mem.h" | ||
| 37 | #include "libavutil/opt.h" | ||
| 38 | |||
| 39 | #include "libavformat/avformat.h" | ||
| 40 | |||
| 41 | #include "libavcodec/avcodec.h" | ||
| 42 | #include "libavcodec/codec.h" | ||
| 43 | |||
| 44 | #include "libswscale/swscale.h" | ||
| 45 | |||
| 46 | typedef struct FrameChecksum { | ||
| 47 | int64_t ts; | ||
| 48 | uint32_t checksum[4]; | ||
| 49 | } FrameChecksum; | ||
| 50 | |||
| 51 | typedef struct PrivData { | ||
| 52 | AVCodecContext *enc; | ||
| 53 | AVCodecContext *dec; | ||
| 54 | |||
| 55 | int64_t pts_in; | ||
| 56 | |||
| 57 | AVPacket *pkt; | ||
| 58 | AVFrame *frame, *frame_recon; | ||
| 59 | |||
| 60 | struct SwsContext *scaler; | ||
| 61 | |||
| 62 | FrameChecksum *checksums_decoded; | ||
| 63 | size_t nb_checksums_decoded; | ||
| 64 | FrameChecksum *checksums_recon; | ||
| 65 | size_t nb_checksums_recon; | ||
| 66 | } PrivData; | ||
| 67 | |||
| 68 | 68 | static int frame_hash(FrameChecksum **pc, size_t *nb_c, int64_t ts, | |
| 69 | const AVFrame *frame) | ||
| 70 | { | ||
| 71 | FrameChecksum *c; | ||
| 72 | 68 | int shift_h[4] = { 0 }, shift_v[4] = { 0 }; | |
| 73 | |||
| 74 | 68 | c = av_realloc_array(*pc, *nb_c + 1, sizeof(*c)); | |
| 75 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
|
68 | if (!c) |
| 76 | ✗ | return AVERROR(ENOMEM); | |
| 77 | 68 | *pc = c; | |
| 78 | 68 | (*nb_c)++; | |
| 79 | |||
| 80 | 68 | c += *nb_c - 1; | |
| 81 | 68 | memset(c, 0, sizeof(*c)); | |
| 82 | |||
| 83 | 68 | av_pix_fmt_get_chroma_sub_sample(frame->format, &shift_h[1], &shift_v[1]); | |
| 84 | 68 | shift_h[2] = shift_h[1]; | |
| 85 | 68 | shift_v[2] = shift_v[1]; | |
| 86 | |||
| 87 | 68 | c->ts = ts; | |
| 88 |
2/2✓ Branch 0 taken 204 times.
✓ Branch 1 taken 68 times.
|
272 | for (int p = 0; frame->data[p]; p++) { |
| 89 | 204 | const uint8_t *data = frame->data[p]; | |
| 90 | 204 | int linesize = av_image_get_linesize(frame->format, frame->width, p); | |
| 91 | 204 | uint32_t checksum = 0; | |
| 92 | |||
| 93 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | av_assert0(linesize >= 0); |
| 94 | |||
| 95 |
2/2✓ Branch 0 taken 19584 times.
✓ Branch 1 taken 204 times.
|
19788 | for (int j = 0; j < frame->height >> shift_v[p]; j++) { |
| 96 | 19584 | checksum = av_adler32_update(checksum, data, linesize); | |
| 97 | 19584 | data += frame->linesize[p]; | |
| 98 | } | ||
| 99 | |||
| 100 | 204 | c->checksum[p] = checksum; | |
| 101 | } | ||
| 102 | |||
| 103 | 68 | return 0; | |
| 104 | } | ||
| 105 | |||
| 106 | 34 | static int recon_frame_process(PrivData *pd, const AVPacket *pkt) | |
| 107 | { | ||
| 108 | 34 | AVFrame *f = pd->frame_recon; | |
| 109 | int ret; | ||
| 110 | |||
| 111 | 34 | ret = avcodec_receive_frame(pd->enc, f); | |
| 112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (ret < 0) { |
| 113 | ✗ | fprintf(stderr, "Error retrieving a reconstructed frame\n"); | |
| 114 | ✗ | return ret; | |
| 115 | } | ||
| 116 | |||
| 117 | // the encoder's internal format (in which the reconstructed frames are | ||
| 118 | // exported) may be different from the user-facing pixel format | ||
| 119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (f->format != pd->enc->pix_fmt) { |
| 120 | ✗ | if (!pd->scaler) { | |
| 121 | ✗ | pd->scaler = sws_getContext(f->width, f->height, f->format, | |
| 122 | ✗ | f->width, f->height, pd->enc->pix_fmt, | |
| 123 | SWS_BITEXACT, NULL, NULL, NULL); | ||
| 124 | ✗ | if (!pd->scaler) | |
| 125 | ✗ | return AVERROR(ENOMEM); | |
| 126 | } | ||
| 127 | |||
| 128 | ✗ | ret = sws_scale_frame(pd->scaler, pd->frame, f); | |
| 129 | ✗ | if (ret < 0) { | |
| 130 | ✗ | fprintf(stderr, "Error converting pixel formats\n"); | |
| 131 | ✗ | return ret; | |
| 132 | } | ||
| 133 | |||
| 134 | ✗ | av_frame_unref(f); | |
| 135 | ✗ | f = pd->frame; | |
| 136 | } | ||
| 137 | |||
| 138 | 34 | ret = frame_hash(&pd->checksums_recon, &pd->nb_checksums_recon, | |
| 139 | 34 | pkt->pts, f); | |
| 140 | 34 | av_frame_unref(f); | |
| 141 | |||
| 142 | 34 | return 0; | |
| 143 | } | ||
| 144 | |||
| 145 | 38 | static int process_frame(DecodeContext *dc, AVFrame *frame) | |
| 146 | { | ||
| 147 | 38 | PrivData *pd = dc->opaque; | |
| 148 | int ret; | ||
| 149 | |||
| 150 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 36 times.
|
38 | if (!avcodec_is_open(pd->enc)) { |
| 151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!frame) { |
| 152 | ✗ | fprintf(stderr, "No input frames were decoded\n"); | |
| 153 | ✗ | return AVERROR_INVALIDDATA; | |
| 154 | } | ||
| 155 | |||
| 156 | 2 | pd->enc->width = frame->width; | |
| 157 | 2 | pd->enc->height = frame->height; | |
| 158 | 2 | pd->enc->pix_fmt = frame->format; | |
| 159 | 2 | pd->enc->thread_count = dc->decoder->thread_count; | |
| 160 | 2 | pd->enc->thread_type = dc->decoder->thread_type; | |
| 161 | |||
| 162 | // real timestamps do not matter for this test, so we just | ||
| 163 | // pretend the input is 25fps CFR to avoid any timestamp issues | ||
| 164 | 2 | pd->enc->time_base = (AVRational){ 1, 25 }; | |
| 165 | |||
| 166 | 2 | ret = avcodec_open2(pd->enc, NULL, NULL); | |
| 167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
| 168 | ✗ | fprintf(stderr, "Error opening the encoder\n"); | |
| 169 | ✗ | return ret; | |
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 4 times.
|
38 | if (frame) { |
| 174 | 34 | frame->pts = pd->pts_in++; | |
| 175 | |||
| 176 | // avoid forcing coded frame type | ||
| 177 | 34 | frame->pict_type = AV_PICTURE_TYPE_NONE; | |
| 178 | } | ||
| 179 | |||
| 180 | 38 | ret = avcodec_send_frame(pd->enc, frame); | |
| 181 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
38 | if (ret == AVERROR_EOF && !frame) |
| 182 | 2 | return 0; | |
| 183 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | if (ret < 0) { |
| 184 | ✗ | fprintf(stderr, "Error submitting a frame for encoding\n"); | |
| 185 | ✗ | return ret; | |
| 186 | } | ||
| 187 | |||
| 188 | 34 | while (1) { | |
| 189 | 70 | AVPacket *pkt = pd->pkt; | |
| 190 | |||
| 191 | 70 | ret = avcodec_receive_packet(pd->enc, pkt); | |
| 192 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 36 times.
|
70 | if (ret == AVERROR(EAGAIN)) |
| 193 | 34 | break; | |
| 194 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34 times.
|
36 | else if (ret == AVERROR_EOF) |
| 195 | 2 | pkt = NULL; | |
| 196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | else if (ret < 0) { |
| 197 | ✗ | fprintf(stderr, "Error receiving a frame from the encoder\n"); | |
| 198 | ✗ | return ret; | |
| 199 | } | ||
| 200 | |||
| 201 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 2 times.
|
36 | if (pkt) { |
| 202 | 34 | ret = recon_frame_process(pd, pkt); | |
| 203 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (ret < 0) |
| 204 | ✗ | return ret; | |
| 205 | } | ||
| 206 | |||
| 207 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 34 times.
|
36 | if (!avcodec_is_open(pd->dec)) { |
| 208 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!pkt) { |
| 209 | ✗ | fprintf(stderr, "No packets were received from the encoder\n"); | |
| 210 | ✗ | return AVERROR(EINVAL); | |
| 211 | } | ||
| 212 | |||
| 213 | 2 | pd->dec->width = pd->enc->width; | |
| 214 | 2 | pd->dec->height = pd->enc->height; | |
| 215 | 2 | pd->dec->pix_fmt = pd->enc->pix_fmt; | |
| 216 | 2 | pd->dec->thread_count = dc->decoder->thread_count; | |
| 217 | 2 | pd->dec->thread_type = dc->decoder->thread_type; | |
| 218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (pd->enc->extradata_size) { |
| 219 | ✗ | pd->dec->extradata = av_memdup(pd->enc->extradata, | |
| 220 | ✗ | pd->enc->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); | |
| 221 | ✗ | if (!pd->dec->extradata) | |
| 222 | ✗ | return AVERROR(ENOMEM); | |
| 223 | } | ||
| 224 | |||
| 225 | 2 | ret = avcodec_open2(pd->dec, NULL, NULL); | |
| 226 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
| 227 | ✗ | fprintf(stderr, "Error opening the decoder\n"); | |
| 228 | ✗ | return ret; | |
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | 36 | ret = avcodec_send_packet(pd->dec, pkt); | |
| 233 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | if (ret < 0) { |
| 234 | ✗ | fprintf(stderr, "Error sending a packet to decoder\n"); | |
| 235 | ✗ | return ret; | |
| 236 | } | ||
| 237 | |||
| 238 | while (1) { | ||
| 239 | 70 | ret = avcodec_receive_frame(pd->dec, pd->frame); | |
| 240 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 36 times.
|
70 | if (ret == AVERROR(EAGAIN)) |
| 241 | 34 | break; | |
| 242 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34 times.
|
36 | else if (ret == AVERROR_EOF) |
| 243 | 2 | return 0; | |
| 244 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | else if (ret < 0) { |
| 245 | ✗ | fprintf(stderr, "Error receiving a frame from decoder\n"); | |
| 246 | ✗ | return ret; | |
| 247 | } | ||
| 248 | |||
| 249 | 34 | ret = frame_hash(&pd->checksums_decoded, &pd->nb_checksums_decoded, | |
| 250 | 34 | pd->frame->pts, pd->frame); | |
| 251 | 34 | av_frame_unref(pd->frame); | |
| 252 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (ret < 0) |
| 253 | ✗ | return ret; | |
| 254 | } | ||
| 255 | |||
| 256 | } | ||
| 257 | |||
| 258 | 34 | return 0; | |
| 259 | } | ||
| 260 | |||
| 261 | 66 | static int frame_checksum_compare(const void *a, const void *b) | |
| 262 | { | ||
| 263 | 66 | const FrameChecksum *ca = a; | |
| 264 | 66 | const FrameChecksum *cb = b; | |
| 265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | if (ca->ts == cb->ts) |
| 266 | ✗ | return 0; | |
| 267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
66 | return FFSIGN(ca->ts - cb->ts); |
| 268 | } | ||
| 269 | |||
| 270 | 2 | int main(int argc, char **argv) | |
| 271 | { | ||
| 272 | PrivData pd; | ||
| 273 | DecodeContext dc; | ||
| 274 | |||
| 275 | 2 | const char *filename, *enc_name, *enc_opts, *thread_type = NULL, *nb_threads = NULL; | |
| 276 | const AVCodec *enc, *dec; | ||
| 277 | 2 | int ret = 0, max_frames = 0; | |
| 278 | |||
| 279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (argc < 4) { |
| 280 | ✗ | fprintf(stderr, | |
| 281 | "Usage: %s <input file> <encoder> <encoder options> " | ||
| 282 | "[<max frame count> [<thread count> <thread type>]\n", | ||
| 283 | argv[0]); | ||
| 284 | ✗ | return 0; | |
| 285 | } | ||
| 286 | |||
| 287 | 2 | filename = argv[1]; | |
| 288 | 2 | enc_name = argv[2]; | |
| 289 | 2 | enc_opts = argv[3]; | |
| 290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (argc >= 5) |
| 291 | ✗ | max_frames = strtol(argv[4], NULL, 0); | |
| 292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (argc >= 6) |
| 293 | ✗ | nb_threads = argv[5]; | |
| 294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (argc >= 7) |
| 295 | ✗ | thread_type = argv[6]; | |
| 296 | |||
| 297 | 2 | memset(&dc, 0, sizeof(dc)); | |
| 298 | 2 | memset(&pd, 0, sizeof(pd)); | |
| 299 | |||
| 300 | 2 | enc = avcodec_find_encoder_by_name(enc_name); | |
| 301 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!enc) { |
| 302 | ✗ | fprintf(stderr, "No such encoder: %s\n", enc_name); | |
| 303 | ✗ | return 1; | |
| 304 | } | ||
| 305 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!(enc->capabilities & AV_CODEC_CAP_ENCODER_RECON_FRAME)) { |
| 306 | ✗ | fprintf(stderr, "Encoder '%s' cannot output reconstructed frames\n", | |
| 307 | ✗ | enc->name); | |
| 308 | ✗ | return 1; | |
| 309 | } | ||
| 310 | |||
| 311 | 2 | dec = avcodec_find_decoder(enc->id); | |
| 312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!dec) { |
| 313 | ✗ | fprintf(stderr, "No decoder for: %s\n", avcodec_get_name(enc->id)); | |
| 314 | ✗ | return 1; | |
| 315 | } | ||
| 316 | |||
| 317 | 2 | pd.enc = avcodec_alloc_context3(enc); | |
| 318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!pd.enc) { |
| 319 | ✗ | fprintf(stderr, "Error allocating encoder\n"); | |
| 320 | ✗ | return 1; | |
| 321 | } | ||
| 322 | |||
| 323 | 2 | ret = av_set_options_string(pd.enc, enc_opts, "=", ","); | |
| 324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
| 325 | ✗ | fprintf(stderr, "Error setting encoder options\n"); | |
| 326 | ✗ | goto fail; | |
| 327 | } | ||
| 328 | 2 | pd.enc->flags |= AV_CODEC_FLAG_RECON_FRAME | AV_CODEC_FLAG_BITEXACT; | |
| 329 | |||
| 330 | 2 | pd.dec = avcodec_alloc_context3(dec); | |
| 331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!pd.dec) { |
| 332 | ✗ | fprintf(stderr, "Error allocating decoder\n"); | |
| 333 | ✗ | goto fail; | |
| 334 | } | ||
| 335 | |||
| 336 | 2 | pd.dec->flags |= AV_CODEC_FLAG_BITEXACT; | |
| 337 | 2 | pd.dec->err_recognition |= AV_EF_CRCCHECK; | |
| 338 | |||
| 339 | 2 | pd.frame = av_frame_alloc(); | |
| 340 | 2 | pd.frame_recon = av_frame_alloc(); | |
| 341 | 2 | pd.pkt = av_packet_alloc(); | |
| 342 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (!pd.frame ||!pd.frame_recon || !pd.pkt) { |
| 343 | ✗ | ret = 1; | |
| 344 | ✗ | goto fail; | |
| 345 | } | ||
| 346 | |||
| 347 | 2 | ret = ds_open(&dc, filename, 0); | |
| 348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
| 349 | ✗ | fprintf(stderr, "Error opening the file\n"); | |
| 350 | ✗ | goto fail; | |
| 351 | } | ||
| 352 | |||
| 353 | 2 | dc.process_frame = process_frame; | |
| 354 | 2 | dc.opaque = &pd; | |
| 355 | 2 | dc.max_frames = max_frames; | |
| 356 | |||
| 357 | 2 | ret = av_dict_set(&dc.decoder_opts, "threads", nb_threads, 0); | |
| 358 | 2 | ret |= av_dict_set(&dc.decoder_opts, "thread_type", thread_type, 0); | |
| 359 | |||
| 360 | 2 | ret = ds_run(&dc); | |
| 361 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
| 362 | ✗ | goto fail; | |
| 363 | |||
| 364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (pd.nb_checksums_decoded != pd.nb_checksums_recon) { |
| 365 | ✗ | fprintf(stderr, "Mismatching frame counts: recon=%zu decoded=%zu\n", | |
| 366 | pd.nb_checksums_recon, pd.nb_checksums_decoded); | ||
| 367 | ✗ | ret = 1; | |
| 368 | ✗ | goto fail; | |
| 369 | } | ||
| 370 | |||
| 371 | // reconstructed frames are in coded order, sort them by pts into presentation order | ||
| 372 | 2 | qsort(pd.checksums_recon, pd.nb_checksums_recon, sizeof(*pd.checksums_recon), | |
| 373 | frame_checksum_compare); | ||
| 374 | |||
| 375 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 2 times.
|
36 | for (size_t i = 0; i < pd.nb_checksums_decoded; i++) { |
| 376 | 34 | const FrameChecksum *d = &pd.checksums_decoded[i]; | |
| 377 | 34 | const FrameChecksum *r = &pd.checksums_recon[i]; | |
| 378 | |||
| 379 |
2/2✓ Branch 0 taken 136 times.
✓ Branch 1 taken 34 times.
|
170 | for (int p = 0; p < FF_ARRAY_ELEMS(d->checksum); p++) |
| 380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
|
136 | if (d->checksum[p] != r->checksum[p]) { |
| 381 | ✗ | fprintf(stderr, "Checksum mismatch in frame ts=%"PRId64", plane %d\n", | |
| 382 | ✗ | d->ts, p); | |
| 383 | ✗ | ret = 1; | |
| 384 | ✗ | goto fail; | |
| 385 | } | ||
| 386 | } | ||
| 387 | 2 | fprintf(stderr, "All %zu encoded frames match\n", pd.nb_checksums_decoded); | |
| 388 | |||
| 389 | 2 | fail: | |
| 390 | 2 | avcodec_free_context(&pd.enc); | |
| 391 | 2 | avcodec_free_context(&pd.dec); | |
| 392 | 2 | av_freep(&pd.checksums_decoded); | |
| 393 | 2 | av_freep(&pd.checksums_recon); | |
| 394 | 2 | av_frame_free(&pd.frame); | |
| 395 | 2 | av_frame_free(&pd.frame_recon); | |
| 396 | 2 | av_packet_free(&pd.pkt); | |
| 397 | 2 | ds_free(&dc); | |
| 398 | 2 | return !!ret; | |
| 399 | } | ||
| 400 |