aomdec.c 34.3 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
Yaowu Xu's avatar
Yaowu Xu committed
2
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
John Koleszar's avatar
John Koleszar committed
3
 *
Yaowu Xu's avatar
Yaowu Xu committed
4 5 6 7 8 9
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
John Koleszar's avatar
John Koleszar committed
10 11
 */

12
#include <assert.h>
John Koleszar's avatar
John Koleszar committed
13 14 15 16
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
17
#include <limits.h>
18

Yaowu Xu's avatar
Yaowu Xu committed
19
#include "./aom_config.h"
20

James Zern's avatar
James Zern committed
21 22 23 24 25 26 27 28
#if CONFIG_OS_SUPPORT
#if HAVE_UNISTD_H
#include <unistd.h>  // NOLINT
#elif !defined(STDOUT_FILENO)
#define STDOUT_FILENO 1
#endif
#endif

29
#if CONFIG_LIBYUV
30
#include "third_party/libyuv/include/libyuv/scale.h"
31
#endif
32 33

#include "./args.h"
34 35
#include "./ivfdec.h"

Yaowu Xu's avatar
Yaowu Xu committed
36
#include "aom/aom_decoder.h"
37
#include "aom_ports/mem_ops.h"
Yaowu Xu's avatar
Yaowu Xu committed
38
#include "aom_ports/aom_timer.h"
39

Yaowu Xu's avatar
Yaowu Xu committed
40 41
#if CONFIG_AV1_DECODER
#include "aom/aomdx.h"
John Koleszar's avatar
John Koleszar committed
42
#endif
43

44
#include "./md5_utils.h"
45 46

#include "./tools_common.h"
47
#if CONFIG_WEBM_IO
48
#include "./webmdec.h"
49
#endif
50
#include "./y4menc.h"
John Koleszar's avatar
John Koleszar committed
51 52 53

static const char *exec_name;

Yaowu Xu's avatar
Yaowu Xu committed
54 55
struct AvxDecInputContext {
  struct AvxInputContext *aom_input_ctx;
56 57 58
  struct WebmInputContext *webm_ctx;
};

clang-format's avatar
clang-format committed
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static const arg_def_t looparg =
    ARG_DEF(NULL, "loops", 1, "Number of times to decode the file");
static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, "Codec to use");
static const arg_def_t use_yv12 =
    ARG_DEF(NULL, "yv12", 0, "Output raw YV12 frames");
static const arg_def_t use_i420 =
    ARG_DEF(NULL, "i420", 0, "Output raw I420 frames");
static const arg_def_t flipuvarg =
    ARG_DEF(NULL, "flipuv", 0, "Flip the chroma planes in the output");
static const arg_def_t rawvideo =
    ARG_DEF(NULL, "rawvideo", 0, "Output raw YUV frames");
static const arg_def_t noblitarg =
    ARG_DEF(NULL, "noblit", 0, "Don't process the decoded frames");
static const arg_def_t progressarg =
    ARG_DEF(NULL, "progress", 0, "Show progress after each frame decodes");
static const arg_def_t limitarg =
    ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames");
static const arg_def_t skiparg =
    ARG_DEF(NULL, "skip", 1, "Skip the first n input frames");
static const arg_def_t postprocarg =
    ARG_DEF(NULL, "postproc", 0, "Postprocess decoded frames");
static const arg_def_t summaryarg =
    ARG_DEF(NULL, "summary", 0, "Show timing summary");
static const arg_def_t outputfile =
    ARG_DEF("o", "output", 1, "Output file name pattern (see below)");
static const arg_def_t threadsarg =
    ARG_DEF("t", "threads", 1, "Max threads to use");
static const arg_def_t frameparallelarg =
    ARG_DEF(NULL, "frame-parallel", 0, "Frame parallel decode");
static const arg_def_t verbosearg =
    ARG_DEF("v", "verbose", 0, "Show version string");
static const arg_def_t error_concealment =
    ARG_DEF(NULL, "error-concealment", 0, "Enable decoder error-concealment");
static const arg_def_t scalearg =
    ARG_DEF("S", "scale", 0, "Scale output frames uniformly");
static const arg_def_t continuearg =
    ARG_DEF("k", "keep-going", 0, "(debug) Continue decoding after error");
static const arg_def_t fb_arg =
    ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use");
static const arg_def_t md5arg =
    ARG_DEF(NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
100 101
static const arg_def_t framestatsarg =
    ARG_DEF(NULL, "framestats", 1, "Output per-frame stats (.csv format)");
Yaowu Xu's avatar
Yaowu Xu committed
102
#if CONFIG_AOM_HIGHBITDEPTH
clang-format's avatar
clang-format committed
103 104
static const arg_def_t outbitdeptharg =
    ARG_DEF(NULL, "output-bit-depth", 1, "Output bit-depth for decoded frames");
105
#endif
106
#if CONFIG_EXT_TILE
clang-format's avatar
clang-format committed
107 108 109 110 111 112
static const arg_def_t tiler = ARG_DEF(NULL, "tile-row", 1,
                                       "Row index of tile to decode "
                                       "(-1 for all rows)");
static const arg_def_t tilec = ARG_DEF(NULL, "tile-column", 1,
                                       "Column index of tile to decode "
                                       "(-1 for all columns)");
113
#endif  // CONFIG_EXT_TILE
Dmitry Kovalev's avatar
Dmitry Kovalev committed
114

clang-format's avatar
clang-format committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
static const arg_def_t *all_args[] = { &codecarg,
                                       &use_yv12,
                                       &use_i420,
                                       &flipuvarg,
                                       &rawvideo,
                                       &noblitarg,
                                       &progressarg,
                                       &limitarg,
                                       &skiparg,
                                       &postprocarg,
                                       &summaryarg,
                                       &outputfile,
                                       &threadsarg,
                                       &frameparallelarg,
                                       &verbosearg,
                                       &scalearg,
                                       &fb_arg,
                                       &md5arg,
133
                                       &framestatsarg,
clang-format's avatar
clang-format committed
134 135
                                       &error_concealment,
                                       &continuearg,
Yaowu Xu's avatar
Yaowu Xu committed
136
#if CONFIG_AOM_HIGHBITDEPTH
clang-format's avatar
clang-format committed
137
                                       &outbitdeptharg,
138
#endif
139
#if CONFIG_EXT_TILE
clang-format's avatar
clang-format committed
140 141
                                       &tiler,
                                       &tilec,
142
#endif  // CONFIG_EXT_TILE
clang-format's avatar
clang-format committed
143
                                       NULL };
John Koleszar's avatar
John Koleszar committed
144

145
#if CONFIG_LIBYUV
Yaowu Xu's avatar
Yaowu Xu committed
146
static INLINE int libyuv_scale(aom_image_t *src, aom_image_t *dst,
clang-format's avatar
clang-format committed
147
                               FilterModeEnum mode) {
Yaowu Xu's avatar
Yaowu Xu committed
148 149 150
#if CONFIG_AOM_HIGHBITDEPTH
  if (src->fmt == AOM_IMG_FMT_I42016) {
    assert(dst->fmt == AOM_IMG_FMT_I42016);
clang-format's avatar
clang-format committed
151
    return I420Scale_16(
Yaowu Xu's avatar
Yaowu Xu committed
152 153 154 155 156 157 158
        (uint16_t *)src->planes[AOM_PLANE_Y], src->stride[AOM_PLANE_Y] / 2,
        (uint16_t *)src->planes[AOM_PLANE_U], src->stride[AOM_PLANE_U] / 2,
        (uint16_t *)src->planes[AOM_PLANE_V], src->stride[AOM_PLANE_V] / 2,
        src->d_w, src->d_h, (uint16_t *)dst->planes[AOM_PLANE_Y],
        dst->stride[AOM_PLANE_Y] / 2, (uint16_t *)dst->planes[AOM_PLANE_U],
        dst->stride[AOM_PLANE_U] / 2, (uint16_t *)dst->planes[AOM_PLANE_V],
        dst->stride[AOM_PLANE_V] / 2, dst->d_w, dst->d_h, mode);
159 160
  }
#endif
Yaowu Xu's avatar
Yaowu Xu committed
161 162 163 164 165 166 167 168
  assert(src->fmt == AOM_IMG_FMT_I420);
  assert(dst->fmt == AOM_IMG_FMT_I420);
  return I420Scale(src->planes[AOM_PLANE_Y], src->stride[AOM_PLANE_Y],
                   src->planes[AOM_PLANE_U], src->stride[AOM_PLANE_U],
                   src->planes[AOM_PLANE_V], src->stride[AOM_PLANE_V], src->d_w,
                   src->d_h, dst->planes[AOM_PLANE_Y], dst->stride[AOM_PLANE_Y],
                   dst->planes[AOM_PLANE_U], dst->stride[AOM_PLANE_U],
                   dst->planes[AOM_PLANE_V], dst->stride[AOM_PLANE_V], dst->d_w,
clang-format's avatar
clang-format committed
169
                   dst->d_h, mode);
170
}
171
#endif
172

173
void usage_exit(void) {
John Koleszar's avatar
John Koleszar committed
174
  int i;
John Koleszar's avatar
John Koleszar committed
175

clang-format's avatar
clang-format committed
176 177 178 179
  fprintf(stderr,
          "Usage: %s <options> filename\n\n"
          "Options:\n",
          exec_name);
John Koleszar's avatar
John Koleszar committed
180 181 182 183 184 185 186
  arg_show_usage(stderr, all_args);
  fprintf(stderr,
          "\nOutput File Patterns:\n\n"
          "  The -o argument specifies the name of the file(s) to "
          "write to. If the\n  argument does not include any escape "
          "characters, the output will be\n  written to a single file. "
          "Otherwise, the filename will be calculated by\n  expanding "
John Koleszar's avatar
John Koleszar committed
187 188
          "the following escape characters:\n");
  fprintf(stderr,
John Koleszar's avatar
John Koleszar committed
189 190 191 192 193
          "\n\t%%w   - Frame width"
          "\n\t%%h   - Frame height"
          "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"
          "\n\n  Pattern arguments are only supported in conjunction "
          "with the --yv12 and\n  --i420 options. If the -o option is "
clang-format's avatar
clang-format committed
194
          "not specified, the output will be\n  directed to stdout.\n");
John Koleszar's avatar
John Koleszar committed
195 196
  fprintf(stderr, "\nIncluded decoders:\n\n");

Yaowu Xu's avatar
Yaowu Xu committed
197 198
  for (i = 0; i < get_aom_decoder_count(); ++i) {
    const AvxInterface *const decoder = get_aom_decoder_by_index(i);
clang-format's avatar
clang-format committed
199
    fprintf(stderr, "    %-6s - %s\n", decoder->name,
Yaowu Xu's avatar
Yaowu Xu committed
200
            aom_codec_iface_name(decoder->codec_interface()));
201
  }
John Koleszar's avatar
John Koleszar committed
202 203

  exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
204 205
}

clang-format's avatar
clang-format committed
206 207
static int raw_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read,
                          size_t *buffer_size) {
208
  char raw_hdr[RAW_FRAME_HDR_SZ];
209
  size_t frame_size = 0;
John Koleszar's avatar
John Koleszar committed
210

211
  if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) {
clang-format's avatar
clang-format committed
212
    if (!feof(infile)) warn("Failed to read RAW frame size\n");
213
  } else {
214 215
    const size_t kCorruptFrameThreshold = 256 * 1024 * 1024;
    const size_t kFrameTooSmallThreshold = 256 * 1024;
216
    frame_size = mem_get_le32(raw_hdr);
John Koleszar's avatar
John Koleszar committed
217

218 219 220 221
    if (frame_size > kCorruptFrameThreshold) {
      warn("Read invalid frame size (%u)\n", (unsigned int)frame_size);
      frame_size = 0;
    }
John Koleszar's avatar
John Koleszar committed
222

223 224 225
    if (frame_size < kFrameTooSmallThreshold) {
      warn("Warning: Read invalid frame size (%u) - not a raw file?\n",
           (unsigned int)frame_size);
John Koleszar's avatar
John Koleszar committed
226
    }
John Koleszar's avatar
John Koleszar committed
227

228 229 230 231 232 233 234 235
    if (frame_size > *buffer_size) {
      uint8_t *new_buf = realloc(*buffer, 2 * frame_size);
      if (new_buf) {
        *buffer = new_buf;
        *buffer_size = 2 * frame_size;
      } else {
        warn("Failed to allocate compressed data buffer\n");
        frame_size = 0;
236
      }
John Koleszar's avatar
John Koleszar committed
237
    }
238
  }
John Koleszar's avatar
John Koleszar committed
239

240 241 242 243 244 245
  if (!feof(infile)) {
    if (fread(*buffer, 1, frame_size, infile) != frame_size) {
      warn("Failed to read full frame\n");
      return 1;
    }
    *bytes_read = frame_size;
John Koleszar's avatar
John Koleszar committed
246 247
  }

248 249 250
  return 0;
}

Yaowu Xu's avatar
Yaowu Xu committed
251
static int read_frame(struct AvxDecInputContext *input, uint8_t **buf,
252
                      size_t *bytes_in_buffer, size_t *buffer_size) {
Yaowu Xu's avatar
Yaowu Xu committed
253
  switch (input->aom_input_ctx->file_type) {
254
#if CONFIG_WEBM_IO
255
    case FILE_TYPE_WEBM:
256
      return webm_read_frame(input->webm_ctx, buf, bytes_in_buffer);
257
#endif
258
    case FILE_TYPE_RAW:
Yaowu Xu's avatar
Yaowu Xu committed
259
      return raw_read_frame(input->aom_input_ctx->file, buf, bytes_in_buffer,
clang-format's avatar
clang-format committed
260
                            buffer_size);
261
    case FILE_TYPE_IVF:
Yaowu Xu's avatar
Yaowu Xu committed
262
      return ivf_read_frame(input->aom_input_ctx->file, buf, bytes_in_buffer,
clang-format's avatar
clang-format committed
263 264
                            buffer_size);
    default: return 1;
265
  }
John Koleszar's avatar
John Koleszar committed
266 267
}

Yaowu Xu's avatar
Yaowu Xu committed
268
static void update_image_md5(const aom_image_t *img, const int planes[3],
269 270 271 272 273 274 275
                             MD5Context *md5) {
  int i, y;

  for (i = 0; i < 3; ++i) {
    const int plane = planes[i];
    const unsigned char *buf = img->planes[plane];
    const int stride = img->stride[plane];
Yaowu Xu's avatar
Yaowu Xu committed
276 277 278
    const int w = aom_img_plane_width(img, plane) *
                  ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
    const int h = aom_img_plane_height(img, plane);
279 280 281 282 283 284 285 286

    for (y = 0; y < h; ++y) {
      MD5Update(md5, buf, w);
      buf += stride;
    }
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
287
static void write_image_file(const aom_image_t *img, const int planes[3],
288 289
                             FILE *file) {
  int i, y;
Yaowu Xu's avatar
Yaowu Xu committed
290 291
#if CONFIG_AOM_HIGHBITDEPTH
  const int bytes_per_sample = ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
292 293 294
#else
  const int bytes_per_sample = 1;
#endif
295 296 297 298 299

  for (i = 0; i < 3; ++i) {
    const int plane = planes[i];
    const unsigned char *buf = img->planes[plane];
    const int stride = img->stride[plane];
Yaowu Xu's avatar
Yaowu Xu committed
300 301
    const int w = aom_img_plane_width(img, plane);
    const int h = aom_img_plane_height(img, plane);
302 303

    for (y = 0; y < h; ++y) {
304
      fwrite(buf, bytes_per_sample, w, file);
305 306
      buf += stride;
    }
John Koleszar's avatar
John Koleszar committed
307
  }
John Koleszar's avatar
John Koleszar committed
308 309
}

Yaowu Xu's avatar
Yaowu Xu committed
310
static int file_is_raw(struct AvxInputContext *input) {
311
  uint8_t buf[32];
John Koleszar's avatar
John Koleszar committed
312
  int is_raw = 0;
Yaowu Xu's avatar
Yaowu Xu committed
313
  aom_codec_stream_info_t si;
314

John Koleszar's avatar
John Koleszar committed
315 316
  si.sz = sizeof(si);

317
  if (fread(buf, 1, 32, input->file) == 32) {
John Koleszar's avatar
John Koleszar committed
318 319
    int i;

320
    if (mem_get_le32(buf) < 256 * 1024 * 1024) {
Yaowu Xu's avatar
Yaowu Xu committed
321 322 323
      for (i = 0; i < get_aom_decoder_count(); ++i) {
        const AvxInterface *const decoder = get_aom_decoder_by_index(i);
        if (!aom_codec_peek_stream_info(decoder->codec_interface(), buf + 4,
clang-format's avatar
clang-format committed
324
                                        32 - 4, &si)) {
John Koleszar's avatar
John Koleszar committed
325
          is_raw = 1;
326
          input->fourcc = decoder->fourcc;
327 328 329 330
          input->width = si.w;
          input->height = si.h;
          input->framerate.numerator = 30;
          input->framerate.denominator = 1;
John Koleszar's avatar
John Koleszar committed
331 332
          break;
        }
333 334
      }
    }
John Koleszar's avatar
John Koleszar committed
335 336
  }

337
  rewind(input->file);
John Koleszar's avatar
John Koleszar committed
338
  return is_raw;
339 340
}

341
static void show_progress(int frame_in, int frame_out, uint64_t dx_time) {
342
  fprintf(stderr,
clang-format's avatar
clang-format committed
343
          "%d decoded frames/%d showed frames in %" PRId64 " us (%.2f fps)\r",
John Koleszar's avatar
John Koleszar committed
344
          frame_in, frame_out, dx_time,
345
          (double)frame_out * 1000000.0 / (double)dx_time);
346 347
}

348
struct ExternalFrameBuffer {
clang-format's avatar
clang-format committed
349
  uint8_t *data;
350 351 352 353 354 355 356 357 358
  size_t size;
  int in_use;
};

struct ExternalFrameBufferList {
  int num_external_frame_buffers;
  struct ExternalFrameBuffer *ext_fb;
};

359
// Callback used by libaom to request an external frame buffer. |cb_priv|
360 361 362
// Application private data passed into the set function. |min_size| is the
// minimum size in bytes needed to decode the next frame. |fb| pointer to the
// frame buffer.
Yaowu Xu's avatar
Yaowu Xu committed
363 364
static int get_av1_frame_buffer(void *cb_priv, size_t min_size,
                                aom_codec_frame_buffer_t *fb) {
365 366 367
  int i;
  struct ExternalFrameBufferList *const ext_fb_list =
      (struct ExternalFrameBufferList *)cb_priv;
clang-format's avatar
clang-format committed
368
  if (ext_fb_list == NULL) return -1;
369 370 371

  // Find a free frame buffer.
  for (i = 0; i < ext_fb_list->num_external_frame_buffers; ++i) {
clang-format's avatar
clang-format committed
372
    if (!ext_fb_list->ext_fb[i].in_use) break;
373 374
  }

clang-format's avatar
clang-format committed
375
  if (i == ext_fb_list->num_external_frame_buffers) return -1;
376 377 378

  if (ext_fb_list->ext_fb[i].size < min_size) {
    free(ext_fb_list->ext_fb[i].data);
379
    ext_fb_list->ext_fb[i].data = (uint8_t *)calloc(min_size, sizeof(uint8_t));
clang-format's avatar
clang-format committed
380
    if (!ext_fb_list->ext_fb[i].data) return -1;
381 382 383 384 385 386 387 388 389 390 391 392 393

    ext_fb_list->ext_fb[i].size = min_size;
  }

  fb->data = ext_fb_list->ext_fb[i].data;
  fb->size = ext_fb_list->ext_fb[i].size;
  ext_fb_list->ext_fb[i].in_use = 1;

  // Set the frame buffer's private data to point at the external frame buffer.
  fb->priv = &ext_fb_list->ext_fb[i];
  return 0;
}

394
// Callback used by libaom when there are no references to the frame buffer.
395 396
// |cb_priv| user private data passed into the set function. |fb| pointer
// to the frame buffer.
Yaowu Xu's avatar
Yaowu Xu committed
397 398
static int release_av1_frame_buffer(void *cb_priv,
                                    aom_codec_frame_buffer_t *fb) {
399 400 401 402 403 404 405
  struct ExternalFrameBuffer *const ext_fb =
      (struct ExternalFrameBuffer *)fb->priv;
  (void)cb_priv;
  ext_fb->in_use = 0;
  return 0;
}

406 407 408
static void generate_filename(const char *pattern, char *out, size_t q_len,
                              unsigned int d_w, unsigned int d_h,
                              unsigned int frame_in) {
John Koleszar's avatar
John Koleszar committed
409 410 411 412 413 414 415 416 417
  const char *p = pattern;
  char *q = out;

  do {
    char *next_pat = strchr(p, '%');

    if (p == next_pat) {
      size_t pat_len;

John Koleszar's avatar
John Koleszar committed
418
      /* parse the pattern */
John Koleszar's avatar
John Koleszar committed
419 420
      q[q_len - 1] = '\0';
      switch (p[1]) {
clang-format's avatar
clang-format committed
421 422 423 424 425 426 427 428 429 430 431 432
        case 'w': snprintf(q, q_len - 1, "%d", d_w); break;
        case 'h': snprintf(q, q_len - 1, "%d", d_h); break;
        case '1': snprintf(q, q_len - 1, "%d", frame_in); break;
        case '2': snprintf(q, q_len - 1, "%02d", frame_in); break;
        case '3': snprintf(q, q_len - 1, "%03d", frame_in); break;
        case '4': snprintf(q, q_len - 1, "%04d", frame_in); break;
        case '5': snprintf(q, q_len - 1, "%05d", frame_in); break;
        case '6': snprintf(q, q_len - 1, "%06d", frame_in); break;
        case '7': snprintf(q, q_len - 1, "%07d", frame_in); break;
        case '8': snprintf(q, q_len - 1, "%08d", frame_in); break;
        case '9': snprintf(q, q_len - 1, "%09d", frame_in); break;
        default: die("Unrecognized pattern %%%c\n", p[1]); break;
John Koleszar's avatar
John Koleszar committed
433 434 435
      }

      pat_len = strlen(q);
clang-format's avatar
clang-format committed
436
      if (pat_len >= q_len - 1) die("Output filename too long.\n");
John Koleszar's avatar
John Koleszar committed
437 438 439 440 441 442
      q += pat_len;
      p += 2;
      q_len -= pat_len;
    } else {
      size_t copy_len;

John Koleszar's avatar
John Koleszar committed
443
      /* copy the next segment */
John Koleszar's avatar
John Koleszar committed
444 445 446 447 448
      if (!next_pat)
        copy_len = strlen(p);
      else
        copy_len = next_pat - p;

clang-format's avatar
clang-format committed
449
      if (copy_len >= q_len - 1) die("Output filename too long.\n");
John Koleszar's avatar
John Koleszar committed
450 451 452 453 454 455 456 457

      memcpy(q, p, copy_len);
      q[copy_len] = '\0';
      q += copy_len;
      p += copy_len;
      q_len -= copy_len;
    }
  } while (*p);
458 459
}

460 461 462 463 464 465 466
static int is_single_file(const char *outfile_pattern) {
  const char *p = outfile_pattern;

  do {
    p = strchr(p, '%');
    if (p && p[1] >= '1' && p[1] <= '9')
      return 0;  // pattern contains sequence number, so it's not unique
clang-format's avatar
clang-format committed
467
    if (p) p++;
468 469 470 471 472 473 474 475
  } while (p);

  return 1;
}

static void print_md5(unsigned char digest[16], const char *filename) {
  int i;

clang-format's avatar
clang-format committed
476
  for (i = 0; i < 16; ++i) printf("%02x", digest[i]);
477 478 479 480 481 482 483 484 485
  printf("  %s\n", filename);
}

static FILE *open_outfile(const char *name) {
  if (strcmp("-", name) == 0) {
    set_binary_mode(stdout);
    return stdout;
  } else {
    FILE *file = fopen(name, "wb");
clang-format's avatar
clang-format committed
486
    if (!file) fatal("Failed to open output file '%s'", name);
487 488 489 490
    return file;
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
491 492 493 494
#if CONFIG_AOM_HIGHBITDEPTH
static int img_shifted_realloc_required(const aom_image_t *img,
                                        const aom_image_t *shifted,
                                        aom_img_fmt_t required_fmt) {
clang-format's avatar
clang-format committed
495
  return img->d_w != shifted->d_w || img->d_h != shifted->d_h ||
496 497
         required_fmt != shifted->fmt;
}
498 499
#endif

500
static int main_loop(int argc, const char **argv_) {
Yaowu Xu's avatar
Yaowu Xu committed
501
  aom_codec_ctx_t decoder;
clang-format's avatar
clang-format committed
502 503
  char *fn = NULL;
  int i;
James Zern's avatar
James Zern committed
504
  int ret = EXIT_FAILURE;
clang-format's avatar
clang-format committed
505 506 507 508 509 510 511 512 513
  uint8_t *buf = NULL;
  size_t bytes_in_buffer = 0, buffer_size = 0;
  FILE *infile;
  int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
  int do_md5 = 0, progress = 0, frame_parallel = 0;
  int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
  int arg_skip = 0;
  int ec_enabled = 0;
  int keep_going = 0;
Yaowu Xu's avatar
Yaowu Xu committed
514 515
  const AvxInterface *interface = NULL;
  const AvxInterface *fourcc_interface = NULL;
516
  uint64_t dx_time = 0;
clang-format's avatar
clang-format committed
517 518 519 520 521 522 523
  struct arg arg;
  char **argv, **argi, **argj;

  int single_file;
  int use_y4m = 1;
  int opt_yv12 = 0;
  int opt_i420 = 0;
Yaowu Xu's avatar
Yaowu Xu committed
524 525
  aom_codec_dec_cfg_t cfg = { 0, 0, 0 };
#if CONFIG_AOM_HIGHBITDEPTH
clang-format's avatar
clang-format committed
526
  unsigned int output_bit_depth = 0;
527
#endif
528
#if CONFIG_EXT_TILE
clang-format's avatar
clang-format committed
529 530
  int tile_row = -1;
  int tile_col = -1;
531
#endif  // CONFIG_EXT_TILE
clang-format's avatar
clang-format committed
532 533 534
  int frames_corrupted = 0;
  int dec_flags = 0;
  int do_scale = 0;
Yaowu Xu's avatar
Yaowu Xu committed
535 536 537
  aom_image_t *scaled_img = NULL;
#if CONFIG_AOM_HIGHBITDEPTH
  aom_image_t *img_shifted = NULL;
538
#endif
clang-format's avatar
clang-format committed
539 540 541
  int frame_avail, got_data, flush_decoder = 0;
  int num_external_frame_buffers = 0;
  struct ExternalFrameBufferList ext_fb_list = { 0, NULL };
John Koleszar's avatar
John Koleszar committed
542

543
  const char *outfile_pattern = NULL;
clang-format's avatar
clang-format committed
544
  char outfile_name[PATH_MAX] = { 0 };
545 546
  FILE *outfile = NULL;

547 548
  FILE *framestats_file = NULL;

549 550 551
  MD5Context md5_ctx;
  unsigned char md5_digest[16];

Yaowu Xu's avatar
Yaowu Xu committed
552 553
  struct AvxDecInputContext input = { NULL, NULL };
  struct AvxInputContext aom_input_ctx;
554
#if CONFIG_WEBM_IO
555 556
  struct WebmInputContext webm_ctx;
  memset(&(webm_ctx), 0, sizeof(webm_ctx));
557
  input.webm_ctx = &webm_ctx;
558
#endif
Yaowu Xu's avatar
Yaowu Xu committed
559
  input.aom_input_ctx = &aom_input_ctx;
560

John Koleszar's avatar
John Koleszar committed
561 562 563 564 565 566 567 568 569
  /* Parse command line */
  exec_name = argv_[0];
  argv = argv_dup(argc - 1, argv_ + 1);

  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    memset(&arg, 0, sizeof(arg));
    arg.argv_step = 1;

    if (arg_match(&arg, &codecarg, argi)) {
Yaowu Xu's avatar
Yaowu Xu committed
570
      interface = get_aom_decoder_by_name(arg.val);
571 572
      if (!interface)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
John Koleszar's avatar
John Koleszar committed
573 574
    } else if (arg_match(&arg, &looparg, argi)) {
      // no-op
575
    } else if (arg_match(&arg, &outputfile, argi)) {
John Koleszar's avatar
John Koleszar committed
576
      outfile_pattern = arg.val;
577
    } else if (arg_match(&arg, &use_yv12, argi)) {
John Koleszar's avatar
John Koleszar committed
578 579
      use_y4m = 0;
      flipuv = 1;
580
      opt_yv12 = 1;
John Koleszar's avatar
John Koleszar committed
581 582 583
    } else if (arg_match(&arg, &use_i420, argi)) {
      use_y4m = 0;
      flipuv = 0;
584 585 586
      opt_i420 = 1;
    } else if (arg_match(&arg, &rawvideo, argi)) {
      use_y4m = 0;
587
    } else if (arg_match(&arg, &flipuvarg, argi)) {
John Koleszar's avatar
John Koleszar committed
588
      flipuv = 1;
589
    } else if (arg_match(&arg, &noblitarg, argi)) {
John Koleszar's avatar
John Koleszar committed
590
      noblit = 1;
591
    } else if (arg_match(&arg, &progressarg, argi)) {
John Koleszar's avatar
John Koleszar committed
592
      progress = 1;
593
    } else if (arg_match(&arg, &limitarg, argi)) {
John Koleszar's avatar
John Koleszar committed
594
      stop_after = arg_parse_uint(&arg);
595
    } else if (arg_match(&arg, &skiparg, argi)) {
596
      arg_skip = arg_parse_uint(&arg);
597
    } else if (arg_match(&arg, &postprocarg, argi)) {
John Koleszar's avatar
John Koleszar committed
598
      postproc = 1;
599
    } else if (arg_match(&arg, &md5arg, argi)) {
John Koleszar's avatar
John Koleszar committed
600
      do_md5 = 1;
601 602 603 604 605 606 607
    } else if (arg_match(&arg, &framestatsarg, argi)) {
      framestats_file = fopen(arg.val, "w");
      if (!framestats_file) {
        die("Error: Could not open --framestats file (%s) for writing.\n",
            arg.val);
      }
    } else if (arg_match(&arg, &summaryarg, argi)) {
John Koleszar's avatar
John Koleszar committed
608
      summary = 1;
609
    } else if (arg_match(&arg, &threadsarg, argi)) {
John Koleszar's avatar
John Koleszar committed
610
      cfg.threads = arg_parse_uint(&arg);
611
    }
Yaowu Xu's avatar
Yaowu Xu committed
612
#if CONFIG_AV1_DECODER
613 614 615
    else if (arg_match(&arg, &frameparallelarg, argi))
      frame_parallel = 1;
#endif
John Koleszar's avatar
John Koleszar committed
616 617
    else if (arg_match(&arg, &verbosearg, argi))
      quiet = 0;
John Koleszar's avatar
John Koleszar committed
618 619
    else if (arg_match(&arg, &scalearg, argi))
      do_scale = 1;
620 621
    else if (arg_match(&arg, &fb_arg, argi))
      num_external_frame_buffers = arg_parse_uint(&arg);
622 623
    else if (arg_match(&arg, &continuearg, argi))
      keep_going = 1;
Yaowu Xu's avatar
Yaowu Xu committed
624
#if CONFIG_AOM_HIGHBITDEPTH
625 626 627 628
    else if (arg_match(&arg, &outbitdeptharg, argi)) {
      output_bit_depth = arg_parse_uint(&arg);
    }
#endif
629 630 631 632 633 634
#if CONFIG_EXT_TILE
    else if (arg_match(&arg, &tiler, argi))
      tile_row = arg_parse_int(&arg);
    else if (arg_match(&arg, &tilec, argi))
      tile_col = arg_parse_int(&arg);
#endif  // CONFIG_EXT_TILE
John Koleszar's avatar
John Koleszar committed
635 636 637
    else
      argj++;
  }
John Koleszar's avatar
John Koleszar committed
638

John Koleszar's avatar
John Koleszar committed
639 640 641 642
  /* Check for unrecognized options */
  for (argi = argv; *argi; argi++)
    if (argi[0][0] == '-' && strlen(argi[0]) > 1)
      die("Error: Unrecognized option %s\n", *argi);
John Koleszar's avatar
John Koleszar committed
643

John Koleszar's avatar
John Koleszar committed
644 645
  /* Handle non-option arguments */
  fn = argv[0];
John Koleszar's avatar
John Koleszar committed
646

hanno's avatar
hanno committed
647 648
  if (!fn) {
    free(argv);
John Koleszar's avatar
John Koleszar committed
649
    usage_exit();
hanno's avatar
hanno committed
650
  }
John Koleszar's avatar
John Koleszar committed
651 652
  /* Open file */
  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
John Koleszar's avatar
John Koleszar committed
653

John Koleszar's avatar
John Koleszar committed
654
  if (!infile) {
655
    fatal("Failed to open input file '%s'", strcmp(fn, "-") ? fn : "stdin");
John Koleszar's avatar
John Koleszar committed
656
  }
657
#if CONFIG_OS_SUPPORT
John Koleszar's avatar
John Koleszar committed
658
  /* Make sure we don't dump to the terminal, unless forced to with -o - */
James Zern's avatar
James Zern committed
659
  if (!outfile_pattern && isatty(STDOUT_FILENO) && !do_md5 && !noblit) {
John Koleszar's avatar
John Koleszar committed
660 661 662 663 664
    fprintf(stderr,
            "Not dumping raw video to your terminal. Use '-o -' to "
            "override.\n");
    return EXIT_FAILURE;
  }
665
#endif
Yaowu Xu's avatar
Yaowu Xu committed
666 667 668
  input.aom_input_ctx->file = infile;
  if (file_is_ivf(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_IVF;
669
#if CONFIG_WEBM_IO
Yaowu Xu's avatar
Yaowu Xu committed
670 671
  else if (file_is_webm(input.webm_ctx, input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_WEBM;
672
#endif
Yaowu Xu's avatar
Yaowu Xu committed
673 674
  else if (file_is_raw(input.aom_input_ctx))
    input.aom_input_ctx->file_type = FILE_TYPE_RAW;
John Koleszar's avatar
John Koleszar committed
675 676
  else {
    fprintf(stderr, "Unrecognized input file type.\n");
677
#if !CONFIG_WEBM_IO
Yaowu Xu's avatar
Yaowu Xu committed
678
    fprintf(stderr, "aomdec was built without WebM container support.\n");
679
#endif
John Koleszar's avatar
John Koleszar committed
680 681 682 683
    return EXIT_FAILURE;
  }

  outfile_pattern = outfile_pattern ? outfile_pattern : "-";
684
  single_file = is_single_file(outfile_pattern);
John Koleszar's avatar
John Koleszar committed
685

686 687
  if (!noblit && single_file) {
    generate_filename(outfile_pattern, outfile_name, PATH_MAX,
Yaowu Xu's avatar
Yaowu Xu committed
688
                      aom_input_ctx.width, aom_input_ctx.height, 0);
689 690 691 692
    if (do_md5)
      MD5Init(&md5_ctx);
    else
      outfile = open_outfile(outfile_name);
John Koleszar's avatar
John Koleszar committed
693 694 695 696
  }

  if (use_y4m && !noblit) {
    if (!single_file) {
clang-format's avatar
clang-format committed
697 698
      fprintf(stderr,
              "YUV4MPEG2 not supported with output patterns,"
Deb Mukherjee's avatar
Deb Mukherjee committed
699
              " try --i420 or --yv12 or --rawvideo.\n");
John Koleszar's avatar
John Koleszar committed
700
      return EXIT_FAILURE;
701
    }
John Koleszar's avatar
John Koleszar committed
702

703
#if CONFIG_WEBM_IO
Yaowu Xu's avatar
Yaowu Xu committed
704 705
    if (aom_input_ctx.file_type == FILE_TYPE_WEBM) {
      if (webm_guess_framerate(input.webm_ctx, input.aom_input_ctx)) {
clang-format's avatar
clang-format committed
706 707
        fprintf(stderr,
                "Failed to guess framerate -- error parsing "
John Koleszar's avatar
John Koleszar committed
708 709 710
                "webm file?\n");
        return EXIT_FAILURE;
      }
711
    }
712
#endif
John Koleszar's avatar
John Koleszar committed
713 714
  }

Yaowu Xu's avatar
Yaowu Xu committed
715
  fourcc_interface = get_aom_decoder_by_fourcc(aom_input_ctx.fourcc);
716 717 718 719
  if (interface && fourcc_interface && interface != fourcc_interface)
    warn("Header indicates codec: %s\n", fourcc_interface->name);
  else
    interface = fourcc_interface;
John Koleszar's avatar
John Koleszar committed
720

Yaowu Xu's avatar
Yaowu Xu committed
721
  if (!interface) interface = get_aom_decoder_by_index(0);
722

Yaowu Xu's avatar
Yaowu Xu committed
723 724 725 726
  dec_flags = (postproc ? AOM_CODEC_USE_POSTPROC : 0) |
              (ec_enabled ? AOM_CODEC_USE_ERROR_CONCEALMENT : 0) |
              (frame_parallel ? AOM_CODEC_USE_FRAME_THREADING : 0);
  if (aom_codec_dec_init(&decoder, interface->codec_interface(), &cfg,
clang-format's avatar
clang-format committed
727
                         dec_flags)) {
728
    fprintf(stderr, "Failed to initialize decoder: %s\n",
Yaowu Xu's avatar
Yaowu Xu committed
729
            aom_codec_error(&decoder));
James Zern's avatar
James Zern committed
730
    goto fail2;
John Koleszar's avatar
John Koleszar committed
731
  }
John Koleszar's avatar
John Koleszar committed
732

clang-format's avatar
clang-format committed
733
  if (!quiet) fprintf(stderr, "%s\n", decoder.name);
John Koleszar's avatar
John Koleszar committed
734

Yaowu Xu's avatar
Yaowu Xu committed
735
#if CONFIG_AV1_DECODER && CONFIG_EXT_TILE
736 737 738 739 740
  if (aom_codec_control(&decoder, AV1_SET_DECODE_TILE_ROW, tile_row)) {
    fprintf(stderr, "Failed to set decode_tile_row: %s\n",
            aom_codec_error(&decoder));
    goto fail;
  }
741

742 743 744 745
  if (aom_codec_control(&decoder, AV1_SET_DECODE_TILE_COL, tile_col)) {
    fprintf(stderr, "Failed to set decode_tile_col: %s\n",
            aom_codec_error(&decoder));
    goto fail;
746 747
  }
#endif
748

clang-format's avatar
clang-format committed
749
  if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
750
  while (arg_skip) {
clang-format's avatar
clang-format committed
751
    if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) break;
752 753 754
    arg_skip--;
  }

755 756 757 758
  if (num_external_frame_buffers > 0) {
    ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
    ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
        num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
Yaowu Xu's avatar
Yaowu Xu committed
759 760
    if (aom_codec_set_frame_buffer_functions(&decoder, get_av1_frame_buffer,
                                             release_av1_frame_buffer,
clang-format's avatar
clang-format committed
761
                                             &ext_fb_list)) {
762
      fprintf(stderr, "Failed to configure external frame buffers: %s\n",
Yaowu Xu's avatar
Yaowu Xu committed
763
              aom_codec_error(&decoder));
James Zern's avatar
James Zern committed
764
      goto fail;
765 766 767
    }
  }

Scott LaVarnway's avatar
Scott LaVarnway committed
768 769 770
  frame_avail = 1;
  got_data = 0;

771 772
  if (framestats_file) fprintf(framestats_file, "bytes,qp\r\n");

John Koleszar's avatar
John Koleszar committed
773
  /* Decode file */
Scott LaVarnway's avatar
Scott LaVarnway committed
774
  while (frame_avail || got_data) {
Yaowu Xu's avatar
Yaowu Xu committed
775 776 777
    aom_codec_iter_t iter = NULL;
    aom_image_t *img;
    struct aom_usec_timer timer;
clang-format's avatar
clang-format committed
778
    int corrupted = 0;
John Koleszar's avatar
John Koleszar committed
779

Scott LaVarnway's avatar
Scott LaVarnway committed
780 781
    frame_avail = 0;
    if (!stop_after || frame_in < stop_after) {
782
      if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
783 784
        frame_avail = 1;
        frame_in++;
John Koleszar's avatar
John Koleszar committed
785

Yaowu Xu's avatar
Yaowu Xu committed
786
        aom_usec_timer_start(&timer);
John Koleszar's avatar
John Koleszar committed
787

Yaowu Xu's avatar
Yaowu Xu committed
788
        if (aom_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer, NULL,
clang-format's avatar
clang-format committed
789
                             0)) {
Yaowu Xu's avatar
Yaowu Xu committed
790
          const char *detail = aom_codec_error_detail(&decoder);
clang-format's avatar
clang-format committed
791
          warn("Failed to decode frame %d: %s", frame_in,
Yaowu Xu's avatar
Yaowu Xu committed
792
               aom_codec_error(&decoder));
793

clang-format's avatar
clang-format committed
794 795
          if (detail) warn("Additional information: %s", detail);
          if (!keep_going) goto fail;
Scott LaVarnway's avatar
Scott LaVarnway committed
796 797
        }

798 799 800 801 802 803 804 805 806 807
        if (framestats_file) {
          int qp;
          if (aom_codec_control(&decoder, AOMD_GET_LAST_QUANTIZER, &qp)) {
            warn("Failed AOMD_GET_LAST_QUANTIZER: %s",
                 aom_codec_error(&decoder));
            if (!keep_going) goto fail;
          }
          fprintf(framestats_file, "%d,%d\r\n", (int)bytes_in_buffer, qp);
        }

Yaowu Xu's avatar
Yaowu Xu committed
808 809
        aom_usec_timer_mark(&timer);
        dx_time += aom_usec_timer_elapsed(&timer);
810 811
      } else {
        flush_decoder = 1;
Scott LaVarnway's avatar
Scott LaVarnway committed
812
      }
813 814
    } else {
      flush_decoder = 1;
Scott LaVarnway's avatar
Scott LaVarnway committed
815 816
    }

Yaowu Xu's avatar
Yaowu Xu committed
817
    aom_usec_timer_start(&timer);
Scott LaVarnway's avatar
Scott LaVarnway committed
818

819 820
    if (flush_decoder) {
      // Flush the decoder in frame parallel decode.
Yaowu Xu's avatar
Yaowu Xu committed
821 822
      if (aom_codec_decode(&decoder, NULL, 0, NULL, 0)) {
        warn("Failed to flush decoder: %s", aom_codec_error(&decoder));
823 824 825
      }
    }

Scott LaVarnway's avatar
Scott LaVarnway committed
826
    got_data = 0;
Yaowu Xu's avatar
Yaowu Xu committed
827
    if ((img = aom_codec_get_frame(&decoder, &iter))) {
Scott LaVarnway's avatar
Scott LaVarnway committed
828 829
      ++frame_out;
      got_data = 1;
830 831
    }

Yaowu Xu's avatar
Yaowu Xu committed
832 833
    aom_usec_timer_mark(&timer);
    dx_time += (unsigned int)aom_usec_timer_elapsed(&timer);
834

835
    if (!frame_parallel &&
Yaowu Xu's avatar
Yaowu Xu committed
836 837
        aom_codec_control(&decoder, AOMD_GET_FRAME_CORRUPTED, &corrupted)) {
      warn("Failed AOM_GET_FRAME_CORRUPTED: %s", aom_codec_error(&decoder));
clang-format's avatar
clang-format committed
838
      if (!keep_going) goto fail;
839
    }
John Koleszar's avatar
John Koleszar committed
840
    frames_corrupted += corrupted;
John Koleszar's avatar
John Koleszar committed
841

clang-format's avatar
clang-format committed
842
    if (progress) show_progress(frame_in, frame_out, dx_time);
John Koleszar's avatar
John Koleszar committed
843

844
    if (!noblit && img) {
Yaowu Xu's avatar
Yaowu Xu committed
845 846
      const int PLANES_YUV[] = { AOM_PLANE_Y, AOM_PLANE_U, AOM_PLANE_V };
      const int PLANES_YVU[] = { AOM_PLANE_Y, AOM_PLANE_V, AOM_PLANE_U };
847
      const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;
848

849
      if (do_scale) {
850 851 852 853
        if (frame_out == 1) {
          // If the output frames are to be scaled to a fixed display size then
          // use the width and height specified in the container. If either of
          // these is set to 0, use the display size set in the first frame
854 855
          // header. If that is unavailable, use the raw decoded size of the
          // first decoded frame.
Yaowu Xu's avatar
Yaowu Xu committed
856 857
          int render_width = aom_input_ctx.width;
          int render_height = aom_input_ctx.height;
858 859
          if (!render_width || !render_height) {
            int render_size[2];
Yaowu Xu's avatar
Yaowu Xu committed
860
            if (aom_codec_control(&decoder, AV1D_GET_DISPLAY_SIZE,
861
                                  render_size)) {
862
              // As last resort use size of first frame as display size.
863 864
              render_width = img->d_w;
              render_height = img->d_h;
865
            } else {
866 867
              render_width = render_size[0];
              render_height = render_size[1];
868
            }
869
          }
clang-format's avatar
clang-format committed
870
          scaled_img =
Yaowu Xu's avatar
Yaowu Xu committed
871
              aom_img_alloc(NULL, img->fmt, render_width, render_height, 16);
872
          scaled_img->bit_depth = img->bit_depth;
John Koleszar's avatar
John Koleszar committed
873
        }
874

875
        if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
Deb Mukherjee's avatar
Deb Mukherjee committed
876
#if CONFIG_LIBYUV
877
          libyuv_scale(img, scaled_img, kFilterBox);
John Koleszar's avatar
John Koleszar committed
878
          img = scaled_img;
Deb Mukherjee's avatar
Deb Mukherjee committed
879
#else
clang-format's avatar
clang-format committed
880 881
          fprintf(stderr,
                  "Failed  to scale output frame: %s.\n"
Deb Mukherjee's avatar
Deb Mukherjee committed
882 883
                  "Scaling is disabled in this configuration. "
                  "To enable scaling, configure with --enable-libyuv\n",
Yaowu Xu's avatar
Yaowu Xu committed
884
                  aom_codec_error(&decoder));
James Zern's avatar
James Zern committed
885
          goto fail;
Deb Mukherjee's avatar
Deb Mukherjee committed
886
#endif
John Koleszar's avatar
John Koleszar committed
887 888
        }
      }
Yaowu Xu's avatar
Yaowu Xu committed
889
#if CONFIG_AOM_HIGHBITDEPTH
890
      // Default to codec bit depth if output bit depth not set
891
      if (!output_bit_depth && single_file && !do_md5) {
892 893 894
        output_bit_depth = img->bit_depth;
      }
      // Shift up or down if necessary
895
      if (output_bit_depth != 0 && output_bit_depth != img->bit_depth) {
Yaowu Xu's avatar
Yaowu Xu committed
896
        const aom_img_fmt_t shifted_fmt =
clang-format's avatar
clang-format committed
897
            output_bit_depth == 8
Yaowu Xu's avatar
Yaowu Xu committed
898 899
                ? img->fmt ^ (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH)
                : img->fmt | AOM_IMG_FMT_HIGHBITDEPTH;
900 901
        if (img_shifted &&
            img_shifted_realloc_required(img, img_shifted, shifted_fmt)) {
Yaowu Xu's avatar
Yaowu Xu committed
902
          aom_img_free(img_shifted);
903 904
          img_shifted = NULL;
        }
905
        if (!img_shifted) {
clang-format's avatar
clang-format committed
906
          img_shifted =
Yaowu Xu's avatar
Yaowu Xu committed
907
              aom_img_alloc(NULL, shifted_fmt, img->d_w, img->d_h, 16);
908 909 910
          img_shifted->bit_depth = output_bit_depth;
        }
        if (output_bit_depth > img->bit_depth) {
Yaowu Xu's avatar
Yaowu Xu committed
911
          aom_img_upshift(img_shifted, img, output_bit_depth - img->bit_depth);
912
        } else {
Yaowu Xu's avatar
Yaowu Xu committed
913
          aom_img_downshift(img_shifted, img,
914
                            img->bit_depth - output_bit_depth);
915 916 917 918
        }
        img = img_shifted;
      }
#endif
919

920
#if CONFIG_EXT_TILE
Yaowu Xu's avatar
Yaowu Xu committed
921 922
      aom_input_ctx.width = img->d_w;
      aom_input_ctx.height = img->d_h;
923 924
#endif  // CONFIG_EXT_TILE

925
      if (single_file) {
926
        if (use_y4m) {
927
          char y4m_buf[Y4M_BUFFER_SIZE] = { 0 };
928
          size_t len = 0;
Yaowu Xu's avatar
Yaowu Xu committed
929
          if (img->fmt == AOM_IMG_FMT_I440 || img->fmt == AOM_IMG_FMT_I44016) {
Deb Mukherjee's avatar
Deb Mukherjee committed
930 931 932
            fprintf(stderr, "Cannot produce y4m output for 440 sampling.\n");
            goto fail;
          }
933 934
          if (frame_out == 1) {
            // Y4M file header
clang-format's avatar
clang-format committed
935
            len = y4m_write_file_header(
936 937 938
                y4m_buf, sizeof(y4m_buf), aom_input_ctx.width,
                aom_input_ctx.height, &aom_input_ctx.framerate, img->fmt,
                img->bit_depth);
939
            if (do_md5) {
940
              MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
941
            } else {
942
              fputs(y4m_buf, outfile);
943 944 945 946
            }
          }

          // Y4M frame header
947
          len = y4m_write_frame_header(y4m_buf, sizeof(y4m_buf));
948
          if (do_md5) {
949
            MD5Update(&md5_ctx, (md5byte *)y4m_buf, (unsigned int)len);
950
          } else {
951
            fputs(y4m_buf, outfile);
952
          }
953 954 955 956 957
        } else {
          if (frame_out == 1) {
            // Check if --yv12 or --i420 options are consistent with the
            // bit-stream decoded
            if (opt_i420) {
Yaowu Xu's avatar
Yaowu Xu committed
958 959
              if (img->fmt != AOM_IMG_FMT_I420 &&
                  img->fmt != AOM_IMG_FMT_I42016) {
960 961 962 963 964
                fprintf(stderr, "Cannot produce i420 output for bit-stream.\n");
                goto fail;
              }
            }
            if (opt_yv12) {
Yaowu Xu's avatar
Yaowu Xu committed
965 966
              if ((img->fmt != AOM_IMG_FMT_I420 &&
                   img->fmt != AOM_IMG_FMT_YV12) ||
clang-format's avatar
clang-format committed
967
                  img->bit_depth != 8) {
968 969 970 971 972
                fprintf(stderr, "Cannot produce yv12 output for bit-stream.\n");
                goto fail;
              }
            }
          }
973 974
        }

975 976
        if (do_md5) {
          update_image_md5