vpxdec.c 33.6 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
7
 *  in the file PATENTS.  All contributing project authors may
8
 *  be found in the AUTHORS file in the root of the source tree.
John Koleszar's avatar
John Koleszar committed
9 10
 */

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

18 19 20
#include "./vpx_config.h"

#if CONFIG_LIBYUV
21
#include "third_party/libyuv/include/libyuv/scale.h"
22
#endif
23 24

#include "./args.h"
25 26
#include "./ivfdec.h"

John Koleszar's avatar
John Koleszar committed
27
#define VPX_CODEC_DISABLE_COMPAT 1
28
#include "vpx/vpx_decoder.h"
29
#include "vpx_ports/mem_ops.h"
John Koleszar's avatar
John Koleszar committed
30
#include "vpx_ports/vpx_timer.h"
31

32
#if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
33
#include "vpx/vp8dx.h"
John Koleszar's avatar
John Koleszar committed
34
#endif
35

36
#include "./md5_utils.h"
37 38

#include "./tools_common.h"
39
#if CONFIG_WEBM_IO
40
#include "./webmdec.h"
41
#endif
42
#include "./y4menc.h"
John Koleszar's avatar
John Koleszar committed
43 44 45

static const char *exec_name;

46 47 48 49 50
struct VpxDecInputContext {
  struct VpxInputContext *vpx_input_ctx;
  struct WebmInputContext *webm_ctx;
};

51 52
static const arg_def_t looparg = ARG_DEF(NULL, "loops", 1,
                                          "Number of times to decode the file");
John Koleszar's avatar
John Koleszar committed
53
static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
John Koleszar's avatar
John Koleszar committed
54
                                          "Codec to use");
John Koleszar's avatar
John Koleszar committed
55
static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
John Koleszar's avatar
John Koleszar committed
56
                                          "Output raw YV12 frames");
John Koleszar's avatar
John Koleszar committed
57
static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
John Koleszar's avatar
John Koleszar committed
58
                                          "Output raw I420 frames");
John Koleszar's avatar
John Koleszar committed
59
static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
John Koleszar's avatar
John Koleszar committed
60
                                           "Flip the chroma planes in the output");
61 62
static const arg_def_t rawvideo = ARG_DEF(NULL, "rawvideo", 0,
                                          "Output raw YUV frames");
John Koleszar's avatar
John Koleszar committed
63
static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
John Koleszar's avatar
John Koleszar committed
64
                                           "Don't process the decoded frames");
John Koleszar's avatar
John Koleszar committed
65
static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
John Koleszar's avatar
John Koleszar committed
66
                                             "Show progress after each frame decodes");
John Koleszar's avatar
John Koleszar committed
67
static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
John Koleszar's avatar
John Koleszar committed
68
                                          "Stop decoding after n frames");
69 70
static const arg_def_t skiparg = ARG_DEF(NULL, "skip", 1,
                                         "Skip the first n input frames");
John Koleszar's avatar
John Koleszar committed
71
static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
John Koleszar's avatar
John Koleszar committed
72
                                             "Postprocess decoded frames");
John Koleszar's avatar
John Koleszar committed
73
static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
John Koleszar's avatar
John Koleszar committed
74
                                            "Show timing summary");
75
static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
John Koleszar's avatar
John Koleszar committed
76
                                            "Output file name pattern (see below)");
John Koleszar's avatar
John Koleszar committed
77
static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
John Koleszar's avatar
John Koleszar committed
78
                                            "Max threads to use");
79
static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0,
John Koleszar's avatar
John Koleszar committed
80
                                            "Show version string");
81 82
static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0,
                                                   "Enable decoder error-concealment");
83 84
static const arg_def_t scalearg = ARG_DEF("S", "scale", 0,
                                            "Scale output frames uniformly");
85 86
static const arg_def_t continuearg =
    ARG_DEF("k", "keep-going", 0, "(debug) Continue decoding after error");
87

88 89
static const arg_def_t fb_arg =
    ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use");
John Koleszar's avatar
John Koleszar committed
90 91 92

static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
                                        "Compute the MD5 sum of the decoded frame");
Dmitry Kovalev's avatar
Dmitry Kovalev committed
93

John Koleszar's avatar
John Koleszar committed
94
static const arg_def_t *all_args[] = {
95
  &codecarg, &use_yv12, &use_i420, &flipuvarg, &rawvideo, &noblitarg,
96
  &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
97
  &threadsarg, &verbosearg, &scalearg, &fb_arg,
98
  &md5arg, &error_concealment, &continuearg,
John Koleszar's avatar
John Koleszar committed
99
  NULL
John Koleszar's avatar
John Koleszar committed
100 101
};

102
#if CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
103
static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
John Koleszar's avatar
John Koleszar committed
104
                                                "Enable VP8 postproc add noise");
John Koleszar's avatar
John Koleszar committed
105
static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
John Koleszar's avatar
John Koleszar committed
106
                                         "Enable VP8 deblocking");
John Koleszar's avatar
John Koleszar committed
107
static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
John Koleszar's avatar
John Koleszar committed
108
                                                    "Enable VP8 demacroblocking, w/ level");
John Koleszar's avatar
John Koleszar committed
109
static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
John Koleszar's avatar
John Koleszar committed
110
                                               "Enable VP8 visible debug info");
111
static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1,
John Koleszar's avatar
John Koleszar committed
112
                                                   "Display only selected reference frame per macro block");
113
static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1,
John Koleszar's avatar
John Koleszar committed
114
                                                  "Display only selected macro block modes");
115
static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1,
John Koleszar's avatar
John Koleszar committed
116
                                                 "Display only selected block modes");
117
static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1,
John Koleszar's avatar
John Koleszar committed
118
                                             "Draw only selected motion vectors");
119 120
static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0,
                                      "Enable multiframe quality enhancement");
John Koleszar's avatar
John Koleszar committed
121

John Koleszar's avatar
John Koleszar committed
122 123
static const arg_def_t *vp8_pp_args[] = {
  &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
124
  &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe,
John Koleszar's avatar
John Koleszar committed
125
  NULL
John Koleszar's avatar
John Koleszar committed
126 127 128
};
#endif

129
#if CONFIG_LIBYUV
130 131
static INLINE int vpx_image_scale(vpx_image_t *src, vpx_image_t *dst,
                                  FilterModeEnum mode) {
132 133 134 135 136 137 138 139 140 141 142 143
  assert(src->fmt == VPX_IMG_FMT_I420);
  assert(dst->fmt == VPX_IMG_FMT_I420);
  return I420Scale(src->planes[VPX_PLANE_Y], src->stride[VPX_PLANE_Y],
                   src->planes[VPX_PLANE_U], src->stride[VPX_PLANE_U],
                   src->planes[VPX_PLANE_V], src->stride[VPX_PLANE_V],
                   src->d_w, src->d_h,
                   dst->planes[VPX_PLANE_Y], dst->stride[VPX_PLANE_Y],
                   dst->planes[VPX_PLANE_U], dst->stride[VPX_PLANE_U],
                   dst->planes[VPX_PLANE_V], dst->stride[VPX_PLANE_V],
                   dst->d_w, dst->d_h,
                   mode);
}
144
#endif
145

146
void usage_exit() {
John Koleszar's avatar
John Koleszar committed
147
  int i;
John Koleszar's avatar
John Koleszar committed
148

John Koleszar's avatar
John Koleszar committed
149 150 151
  fprintf(stderr, "Usage: %s <options> filename\n\n"
          "Options:\n", exec_name);
  arg_show_usage(stderr, all_args);
152
#if CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
153 154
  fprintf(stderr, "\nVP8 Postprocessing Options:\n");
  arg_show_usage(stderr, vp8_pp_args);
John Koleszar's avatar
John Koleszar committed
155
#endif
John Koleszar's avatar
John Koleszar committed
156 157 158 159 160 161
  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 "
162 163
          "the following escape characters:\n");
  fprintf(stderr,
John Koleszar's avatar
John Koleszar committed
164 165 166 167 168 169 170 171 172
          "\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 "
          "not specified, the output will be\n  directed to stdout.\n"
         );
  fprintf(stderr, "\nIncluded decoders:\n\n");

173 174
  for (i = 0; i < get_vpx_decoder_count(); ++i) {
    const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
John Koleszar's avatar
John Koleszar committed
175
    fprintf(stderr, "    %-6s - %s\n",
176
            decoder->name, vpx_codec_iface_name(decoder->codec_interface()));
177
  }
John Koleszar's avatar
John Koleszar committed
178 179

  exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
180 181
}

182
static int raw_read_frame(FILE *infile, uint8_t **buffer,
183
                          size_t *bytes_read, size_t *buffer_size) {
184
  char raw_hdr[RAW_FRAME_HDR_SZ];
185
  size_t frame_size = 0;
John Koleszar's avatar
John Koleszar committed
186

187 188 189 190
  if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) {
    if (!feof(infile))
      warn("Failed to read RAW frame size\n");
  } else {
191 192
    const size_t kCorruptFrameThreshold = 256 * 1024 * 1024;
    const size_t kFrameTooSmallThreshold = 256 * 1024;
193
    frame_size = mem_get_le32(raw_hdr);
John Koleszar's avatar
John Koleszar committed
194

195 196 197 198
    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
199

200 201 202
    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
203
    }
John Koleszar's avatar
John Koleszar committed
204

205 206 207 208 209 210 211 212
    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;
213
      }
John Koleszar's avatar
John Koleszar committed
214
    }
215
  }
John Koleszar's avatar
John Koleszar committed
216

217 218 219 220 221 222
  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
223 224
  }

225 226 227 228 229 230
  return 0;
}

static int read_frame(struct VpxDecInputContext *input, uint8_t **buf,
                      size_t *bytes_in_buffer, size_t *buffer_size) {
  switch (input->vpx_input_ctx->file_type) {
231
#if CONFIG_WEBM_IO
232 233 234
    case FILE_TYPE_WEBM:
      return webm_read_frame(input->webm_ctx,
                             buf, bytes_in_buffer, buffer_size);
235
#endif
236
    case FILE_TYPE_RAW:
237
      return raw_read_frame(input->vpx_input_ctx->file,
238 239
                            buf, bytes_in_buffer, buffer_size);
    case FILE_TYPE_IVF:
240
      return ivf_read_frame(input->vpx_input_ctx->file,
241 242 243 244
                            buf, bytes_in_buffer, buffer_size);
    default:
      return 1;
  }
John Koleszar's avatar
John Koleszar committed
245 246
}

247 248 249 250 251 252 253 254
static void update_image_md5(const vpx_image_t *img, const int planes[3],
                             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];
255 256
    const int w = vpx_img_plane_width(img, plane);
    const int h = vpx_img_plane_height(img, plane);
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

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

static void write_image_file(const vpx_image_t *img, const int planes[3],
                             FILE *file) {
  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];
273 274
    const int w = vpx_img_plane_width(img, plane);
    const int h = vpx_img_plane_height(img, plane);
275 276 277 278 279

    for (y = 0; y < h; ++y) {
      fwrite(buf, 1, w, file);
      buf += stride;
    }
John Koleszar's avatar
John Koleszar committed
280
  }
John Koleszar's avatar
John Koleszar committed
281 282
}

283 284
int file_is_raw(struct VpxInputContext *input) {
  uint8_t buf[32];
John Koleszar's avatar
John Koleszar committed
285 286
  int is_raw = 0;
  vpx_codec_stream_info_t si;
287

John Koleszar's avatar
John Koleszar committed
288 289
  si.sz = sizeof(si);

290
  if (fread(buf, 1, 32, input->file) == 32) {
John Koleszar's avatar
John Koleszar committed
291 292
    int i;

293
    if (mem_get_le32(buf) < 256 * 1024 * 1024) {
294 295
      for (i = 0; i < get_vpx_decoder_count(); ++i) {
        const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
296
        if (!vpx_codec_peek_stream_info(decoder->codec_interface(),
John Koleszar's avatar
John Koleszar committed
297 298
                                        buf + 4, 32 - 4, &si)) {
          is_raw = 1;
299
          input->fourcc = decoder->fourcc;
300 301 302 303
          input->width = si.w;
          input->height = si.h;
          input->framerate.numerator = 30;
          input->framerate.denominator = 1;
John Koleszar's avatar
John Koleszar committed
304 305
          break;
        }
306 307
      }
    }
John Koleszar's avatar
John Koleszar committed
308 309
  }

310
  rewind(input->file);
John Koleszar's avatar
John Koleszar committed
311
  return is_raw;
312 313
}

314 315 316
void show_progress(int frame_in, int frame_out, uint64_t dx_time) {
  fprintf(stderr,
          "%d decoded frames/%d showed frames in %"PRId64" us (%.2f fps)\r",
John Koleszar's avatar
John Koleszar committed
317
          frame_in, frame_out, dx_time,
318
          (double)frame_out * 1000000.0 / (double)dx_time);
319 320
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
struct ExternalFrameBuffer {
  uint8_t* data;
  size_t size;
  int in_use;
};

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

// Callback used by libvpx to request an external frame buffer. |cb_priv|
// 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.
int get_vp9_frame_buffer(void *cb_priv, size_t min_size,
                         vpx_codec_frame_buffer_t *fb) {
  int i;
  struct ExternalFrameBufferList *const ext_fb_list =
      (struct ExternalFrameBufferList *)cb_priv;
  if (ext_fb_list == NULL)
    return -1;

  // Find a free frame buffer.
  for (i = 0; i < ext_fb_list->num_external_frame_buffers; ++i) {
    if (!ext_fb_list->ext_fb[i].in_use)
      break;
  }

  if (i == ext_fb_list->num_external_frame_buffers)
    return -1;

  if (ext_fb_list->ext_fb[i].size < min_size) {
    free(ext_fb_list->ext_fb[i].data);
    ext_fb_list->ext_fb[i].data = (uint8_t *)malloc(min_size);
    if (!ext_fb_list->ext_fb[i].data)
      return -1;

    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;
}

// Callback used by libvpx when there are no references to the frame buffer.
// |cb_priv| user private data passed into the set function. |fb| pointer
// to the frame buffer.
int release_vp9_frame_buffer(void *cb_priv,
                             vpx_codec_frame_buffer_t *fb) {
  struct ExternalFrameBuffer *const ext_fb =
      (struct ExternalFrameBuffer *)fb->priv;
  (void)cb_priv;
  ext_fb->in_use = 0;
  return 0;
}

383 384
void generate_filename(const char *pattern, char *out, size_t q_len,
                       unsigned int d_w, unsigned int d_h,
John Koleszar's avatar
John Koleszar committed
385 386 387 388 389 390 391 392 393 394
                       unsigned int frame_in) {
  const char *p = pattern;
  char *q = out;

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

    if (p == next_pat) {
      size_t pat_len;

395
      /* parse the pattern */
John Koleszar's avatar
John Koleszar committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
      q[q_len - 1] = '\0';
      switch (p[1]) {
        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]);
433
          break;
John Koleszar's avatar
John Koleszar committed
434 435 436 437 438 439 440 441 442 443 444
      }

      pat_len = strlen(q);
      if (pat_len >= q_len - 1)
        die("Output filename too long.\n");
      q += pat_len;
      p += 2;
      q_len -= pat_len;
    } else {
      size_t copy_len;

445
      /* copy the next segment */
John Koleszar's avatar
John Koleszar committed
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
      if (!next_pat)
        copy_len = strlen(p);
      else
        copy_len = next_pat - p;

      if (copy_len >= q_len - 1)
        die("Output filename too long.\n");

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

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
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
    if (p)
      p++;
  } while (p);

  return 1;
}

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

  for (i = 0; i < 16; ++i)
    printf("%02x", digest[i]);
  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");
    if (!file)
      fatal("Failed to output file %s", name);
    return file;
  }
}

497
int main_loop(int argc, const char **argv_) {
498
  vpx_codec_ctx_t       decoder;
John Koleszar's avatar
John Koleszar committed
499
  char                  *fn = NULL;
500
  int                    i;
John Koleszar's avatar
John Koleszar committed
501
  uint8_t               *buf = NULL;
502
  size_t                 bytes_in_buffer = 0, buffer_size = 0;
John Koleszar's avatar
John Koleszar committed
503
  FILE                  *infile;
504 505
  int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
  int                    do_md5 = 0, progress = 0;
John Koleszar's avatar
John Koleszar committed
506
  int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
507
  int                    arg_skip = 0;
508
  int                    ec_enabled = 0;
509
  int                    keep_going = 0;
510 511
  const VpxInterface *interface = NULL;
  const VpxInterface *fourcc_interface = NULL;
512
  uint64_t dx_time = 0;
John Koleszar's avatar
John Koleszar committed
513 514
  struct arg               arg;
  char                   **argv, **argi, **argj;
515

John Koleszar's avatar
John Koleszar committed
516 517
  int                     single_file;
  int                     use_y4m = 1;
518 519
  int                     opt_yv12 = 0;
  int                     opt_i420 = 0;
520
  vpx_codec_dec_cfg_t     cfg = {0, 0, 0};
521
#if CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
522 523 524 525 526
  vp8_postproc_cfg_t      vp8_pp_cfg = {0};
  int                     vp8_dbg_color_ref_frame = 0;
  int                     vp8_dbg_color_mb_modes = 0;
  int                     vp8_dbg_color_b_modes = 0;
  int                     vp8_dbg_display_mv = 0;
John Koleszar's avatar
John Koleszar committed
527
#endif
John Koleszar's avatar
John Koleszar committed
528 529
  int                     frames_corrupted = 0;
  int                     dec_flags = 0;
530
  int                     do_scale = 0;
531
  vpx_image_t             *scaled_img = NULL;
Scott LaVarnway's avatar
Scott LaVarnway committed
532
  int                     frame_avail, got_data;
533
  int                     num_external_frame_buffers = 0;
534
  struct ExternalFrameBufferList ext_fb_list = {0, NULL};
John Koleszar's avatar
John Koleszar committed
535

536 537 538 539 540 541 542
  const char *outfile_pattern = NULL;
  char outfile_name[PATH_MAX] = {0};
  FILE *outfile = NULL;

  MD5Context md5_ctx;
  unsigned char md5_digest[16];

543 544
  struct VpxDecInputContext input = {NULL, NULL};
  struct VpxInputContext vpx_input_ctx;
545
#if CONFIG_WEBM_IO
546
  struct WebmInputContext webm_ctx = {0};
547
  input.webm_ctx = &webm_ctx;
548 549
#endif
  input.vpx_input_ctx = &vpx_input_ctx;
550

John Koleszar's avatar
John Koleszar committed
551 552 553 554 555 556 557 558 559
  /* 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)) {
560 561 562
      interface = get_vpx_decoder_by_name(arg.val);
      if (!interface)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
563 564
    } else if (arg_match(&arg, &looparg, argi)) {
      // no-op
John Koleszar's avatar
John Koleszar committed
565 566 567 568 569
    } else if (arg_match(&arg, &outputfile, argi))
      outfile_pattern = arg.val;
    else if (arg_match(&arg, &use_yv12, argi)) {
      use_y4m = 0;
      flipuv = 1;
570
      opt_yv12 = 1;
John Koleszar's avatar
John Koleszar committed
571 572 573
    } else if (arg_match(&arg, &use_i420, argi)) {
      use_y4m = 0;
      flipuv = 0;
574 575 576
      opt_i420 = 1;
    } else if (arg_match(&arg, &rawvideo, argi)) {
      use_y4m = 0;
John Koleszar's avatar
John Koleszar committed
577 578 579 580 581 582 583 584
    } else if (arg_match(&arg, &flipuvarg, argi))
      flipuv = 1;
    else if (arg_match(&arg, &noblitarg, argi))
      noblit = 1;
    else if (arg_match(&arg, &progressarg, argi))
      progress = 1;
    else if (arg_match(&arg, &limitarg, argi))
      stop_after = arg_parse_uint(&arg);
585 586
    else if (arg_match(&arg, &skiparg, argi))
      arg_skip = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
587 588 589 590 591 592 593 594 595 596
    else if (arg_match(&arg, &postprocarg, argi))
      postproc = 1;
    else if (arg_match(&arg, &md5arg, argi))
      do_md5 = 1;
    else if (arg_match(&arg, &summaryarg, argi))
      summary = 1;
    else if (arg_match(&arg, &threadsarg, argi))
      cfg.threads = arg_parse_uint(&arg);
    else if (arg_match(&arg, &verbosearg, argi))
      quiet = 0;
597 598
    else if (arg_match(&arg, &scalearg, argi))
      do_scale = 1;
599 600
    else if (arg_match(&arg, &fb_arg, argi))
      num_external_frame_buffers = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
601

602
#if CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
603 604 605 606 607 608 609 610 611 612 613
    else if (arg_match(&arg, &addnoise_level, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
      vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &demacroblock_level, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
      vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &deblock, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
614 615 616
    } else if (arg_match(&arg, &mfqe, argi)) {
      postproc = 1;
      vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
John Koleszar's avatar
John Koleszar committed
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
    } else if (arg_match(&arg, &pp_debug_info, argi)) {
      unsigned int level = arg_parse_uint(&arg);

      postproc = 1;
      vp8_pp_cfg.post_proc_flag &= ~0x7;

      if (level)
        vp8_pp_cfg.post_proc_flag |= level;
    } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_ref_frame = flags;
      }
    } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_mb_modes = flags;
      }
    } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_color_b_modes = flags;
      }
    } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
      unsigned int flags = arg_parse_int(&arg);
      if (flags) {
        postproc = 1;
        vp8_dbg_display_mv = flags;
      }
649 650
    } else if (arg_match(&arg, &error_concealment, argi)) {
      ec_enabled = 1;
651 652
    } else if (arg_match(&arg, &continuearg, argi)) {
      keep_going = 1;
John Koleszar's avatar
John Koleszar committed
653
    }
John Koleszar's avatar
John Koleszar committed
654 655

#endif
John Koleszar's avatar
John Koleszar committed
656 657 658
    else
      argj++;
  }
John Koleszar's avatar
John Koleszar committed
659

John Koleszar's avatar
John Koleszar committed
660 661 662 663
  /* 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
664

John Koleszar's avatar
John Koleszar committed
665 666
  /* Handle non-option arguments */
  fn = argv[0];
John Koleszar's avatar
John Koleszar committed
667

John Koleszar's avatar
John Koleszar committed
668 669
  if (!fn)
    usage_exit();
John Koleszar's avatar
John Koleszar committed
670

John Koleszar's avatar
John Koleszar committed
671 672
  /* Open file */
  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
John Koleszar's avatar
John Koleszar committed
673

John Koleszar's avatar
John Koleszar committed
674
  if (!infile) {
675
    fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin");
John Koleszar's avatar
John Koleszar committed
676 677
    return EXIT_FAILURE;
  }
678
#if CONFIG_OS_SUPPORT
John Koleszar's avatar
John Koleszar committed
679 680 681 682 683 684 685
  /* Make sure we don't dump to the terminal, unless forced to with -o - */
  if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
    fprintf(stderr,
            "Not dumping raw video to your terminal. Use '-o -' to "
            "override.\n");
    return EXIT_FAILURE;
  }
686
#endif
687 688 689
  input.vpx_input_ctx->file = infile;
  if (file_is_ivf(input.vpx_input_ctx))
    input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
690
#if CONFIG_WEBM_IO
691
  else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
692
    input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
693
#endif
694 695
  else if (file_is_raw(input.vpx_input_ctx))
    input.vpx_input_ctx->file_type = FILE_TYPE_RAW;
John Koleszar's avatar
John Koleszar committed
696 697
  else {
    fprintf(stderr, "Unrecognized input file type.\n");
698 699 700
#if !CONFIG_WEBM_IO
    fprintf(stderr, "vpxdec was built without WebM container support.\n");
#endif
John Koleszar's avatar
John Koleszar committed
701 702 703 704
    return EXIT_FAILURE;
  }

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

707 708
  if (!noblit && single_file) {
    generate_filename(outfile_pattern, outfile_name, PATH_MAX,
709
                      vpx_input_ctx.width, vpx_input_ctx.height, 0);
710 711 712 713
    if (do_md5)
      MD5Init(&md5_ctx);
    else
      outfile = open_outfile(outfile_name);
John Koleszar's avatar
John Koleszar committed
714 715 716 717 718 719 720
  }

  if (use_y4m && !noblit) {
    if (!single_file) {
      fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
              " try --i420 or --yv12.\n");
      return EXIT_FAILURE;
721
    }
John Koleszar's avatar
John Koleszar committed
722

723
#if CONFIG_WEBM_IO
724
    if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) {
725
      if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) {
John Koleszar's avatar
John Koleszar committed
726 727 728 729
        fprintf(stderr, "Failed to guess framerate -- error parsing "
                "webm file?\n");
        return EXIT_FAILURE;
      }
730
    }
731
#endif
John Koleszar's avatar
John Koleszar committed
732 733
  }

734 735 736 737 738
  fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc);
  if (interface && fourcc_interface && interface != fourcc_interface)
    warn("Header indicates codec: %s\n", fourcc_interface->name);
  else
    interface = fourcc_interface;
739

740 741
  if (!interface)
    interface = get_vpx_decoder_by_index(0);
742

743 744
  dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
              (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
745 746
  if (vpx_codec_dec_init(&decoder, interface->codec_interface(),
                         &cfg, dec_flags)) {
747 748
    fprintf(stderr, "Failed to initialize decoder: %s\n",
            vpx_codec_error(&decoder));
John Koleszar's avatar
John Koleszar committed
749 750
    return EXIT_FAILURE;
  }
John Koleszar's avatar
John Koleszar committed
751

John Koleszar's avatar
John Koleszar committed
752 753
  if (!quiet)
    fprintf(stderr, "%s\n", decoder.name);
John Koleszar's avatar
John Koleszar committed
754

755
#if CONFIG_VP8_DECODER
John Koleszar's avatar
John Koleszar committed
756

John Koleszar's avatar
John Koleszar committed
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
  if (vp8_pp_cfg.post_proc_flag
      && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
    fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_ref_frame
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
    fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_mb_modes
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
    fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_color_b_modes
      && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
    fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }

  if (vp8_dbg_display_mv
      && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
    fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
    return EXIT_FAILURE;
  }
#endif
John Koleszar's avatar
John Koleszar committed
787

788

789
  if (arg_skip)
790
    fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
791
  while (arg_skip) {
792
    if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size))
793 794 795 796
      break;
    arg_skip--;
  }

797 798 799 800 801 802 803 804 805 806 807 808 809
  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));
    if (vpx_codec_set_frame_buffer_functions(
            &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer,
            &ext_fb_list)) {
      fprintf(stderr, "Failed to configure external frame buffers: %s\n",
              vpx_codec_error(&decoder));
      return EXIT_FAILURE;
    }
  }

Scott LaVarnway's avatar
Scott LaVarnway committed
810 811 812
  frame_avail = 1;
  got_data = 0;

John Koleszar's avatar
John Koleszar committed
813
  /* Decode file */
Scott LaVarnway's avatar
Scott LaVarnway committed
814
  while (frame_avail || got_data) {
John Koleszar's avatar
John Koleszar committed
815 816 817 818
    vpx_codec_iter_t  iter = NULL;
    vpx_image_t    *img;
    struct vpx_usec_timer timer;
    int                   corrupted;
John Koleszar's avatar
John Koleszar committed
819

Scott LaVarnway's avatar
Scott LaVarnway committed
820 821
    frame_avail = 0;
    if (!stop_after || frame_in < stop_after) {
822
      if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
823 824
        frame_avail = 1;
        frame_in++;
John Koleszar's avatar
John Koleszar committed
825

Scott LaVarnway's avatar
Scott LaVarnway committed
826
        vpx_usec_timer_start(&timer);
John Koleszar's avatar
John Koleszar committed
827

828 829
        if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer,
                             NULL, 0)) {
Scott LaVarnway's avatar
Scott LaVarnway committed
830
          const char *detail = vpx_codec_error_detail(&decoder);
831 832
          warn("Failed to decode frame %d: %s",
               frame_in, vpx_codec_error(&decoder));
833

Scott LaVarnway's avatar
Scott LaVarnway committed
834
          if (detail)
835
            warn("Additional information: %s", detail);
836 837
          if (!keep_going)
            goto fail;
Scott LaVarnway's avatar
Scott LaVarnway committed
838 839 840
        }

        vpx_usec_timer_mark(&timer);
841
        dx_time += vpx_usec_timer_elapsed(&timer);
Scott LaVarnway's avatar
Scott LaVarnway committed
842 843 844 845 846 847 848 849 850
      }
    }

    vpx_usec_timer_start(&timer);

    got_data = 0;
    if ((img = vpx_codec_get_frame(&decoder, &iter))) {
      ++frame_out;
      got_data = 1;
851 852
    }

John Koleszar's avatar
John Koleszar committed
853
    vpx_usec_timer_mark(&timer);
854
    dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
855

John Koleszar's avatar
John Koleszar committed
856
    if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
857
      warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
John Koleszar's avatar
John Koleszar committed
858
      goto fail;
859
    }
John Koleszar's avatar
John Koleszar committed
860
    frames_corrupted += corrupted;
John Koleszar's avatar
John Koleszar committed
861

John Koleszar's avatar
John Koleszar committed
862 863
    if (progress)
      show_progress(frame_in, frame_out, dx_time);
John Koleszar's avatar
John Koleszar committed
864

865 866 867 868
    if (!noblit && img) {
      const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V};
      const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U};
      const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;
869

870
      if (do_scale) {
871 872 873 874
        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
875 876
          // header. If that is unavailable, use the raw decoded size of the
          // first decoded frame.
877 878
          int display_width = vpx_input_ctx.width;
          int display_height = vpx_input_ctx.height;
879 880 881 882 883 884 885 886 887 888 889
          if (!display_width || !display_height) {
            int display_size[2];
            if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE,
                                  display_size)) {
              // As last resort use size of first frame as display size.
              display_width = img->d_w;
              display_height = img->d_h;
            } else {
              display_width = display_size[0];
              display_height = display_size[1];
            }
890
          }
891 892
          scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width,
                                     display_height, 16);
893
          scaled_img->bit_depth = img->bit_depth;
894
        }
895

896
        if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
897
#if CONFIG_LIBYUV
898
          vpx_image_scale(img, scaled_img, kFilterBox);
899
          img = scaled_img;
900 901 902 903 904 905 906
#else
          fprintf(stderr, "Failed  to scale output frame: %s.\n"
                  "Scaling is disabled in this configuration. "
                  "To enable scaling, configure with --enable-libyuv\n",
                  vpx_codec_error(&decoder));
          return EXIT_FAILURE;
#endif
907 908
        }
      }
909

910
      if (single_file) {
911 912 913 914 915 916 917 918
        if (use_y4m) {
          char buf[Y4M_BUFFER_SIZE] = {0};
          size_t len = 0;
          if (frame_out == 1) {
            // Y4M file header
            len = y4m_write_file_header(buf, sizeof(buf),
                                        vpx_input_ctx.width,
                                        vpx_input_ctx.height,
919
                                        &vpx_input_ctx.framerate,
920
                                        img->fmt, img->bit_depth);
921
            if (do_md5) {
922
              MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
923 924 925 926 927 928 929 930
            } else {
              fputs(buf, outfile);
            }
          }

          // Y4M frame header
          len = y4m_write_frame_header(buf, sizeof(buf));
          if (do_md5) {
931
            MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
932 933 934
          } else {
            fputs(buf, outfile);
          }
935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
        } else {
          if (frame_out == 1) {
            // Check if --yv12 or --i420 options are consistent with the
            // bit-stream decoded
            if (opt_i420) {
              if (img->fmt != VPX_IMG_FMT_I420 &&
                  img->fmt != VPX_IMG_FMT_I42016) {
                fprintf(stderr, "Cannot produce i420 output for bit-stream.\n");
                goto fail;
              }
            }
            if (opt_yv12) {
              if ((img->fmt != VPX_IMG_FMT_I420 &&
                   img->fmt != VPX_IMG_FMT_YV12) || img->bit_depth != 8) {
                fprintf(stderr, "Cannot produce yv12 output for bit-stream.\n");
                goto fail;
              }
            }
          }
954 955
        }

956 957
        if (do_md5) {
          update_image_md5(img, planes, &md5_ctx);
958
        } else {
959 960 961 962 963 964 965 966 967 968 969 970 971 972
          write_image_file(img, planes, outfile);
        }
      } else {
        generate_filename(outfile_pattern, outfile_name, PATH_MAX,
                          img->d_w, img->d_h, frame_in);
        if (do_md5) {
          MD5Init(&md5_ctx);
          update_image_md5(img, planes, &md5_ctx);
          MD5Final(md5_digest, &md5_ctx);
          print_md5(md5_digest, outfile_name);
        } else {
          outfile = open_outfile(outfile_name);
          write_image_file(img, planes, outfile);
          fclose(outfile);
973
        }
John Koleszar's avatar
John Koleszar committed
974
      }
John Koleszar's avatar
John Koleszar committed
975 976
    }

John Koleszar's avatar
John Koleszar committed
977 978 979
    if (stop_after && frame_in >= stop_after)
      break;
  }
John Koleszar's avatar
John Koleszar committed
980

John Koleszar's avatar
John Koleszar committed
981 982 983 984 985 986 987
  if (summary || progress) {
    show_progress(frame_in, frame_out, dx_time);
    fprintf(stderr, "\n");
  }

  if (frames_corrupted)
    fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
988

John Koleszar's avatar
John Koleszar committed
989 990
fail:

John Koleszar's avatar
John Koleszar committed
991
  if (vpx_codec_destroy(&decoder)) {
992 993
    fprintf(stderr, "Failed to destroy decoder: %s\n",
            vpx_codec_error(&decoder));
John Koleszar's avatar
John Koleszar committed
994 995
    return EXIT_FAILURE;
  }
John Koleszar's avatar
John Koleszar committed
996

997 998 999 1000 1001 1002 1003 1004
  if (!noblit && single_file) {
    if (do_md5) {
      MD5Final(md5_digest, &md5_ctx);
      print_md5(md5_digest, outfile_name);
    } else {
      fclose(outfile);
    }
  }
John Koleszar's avatar
John Koleszar committed
1005

1006
#if CONFIG_WEBM_IO
1007 1008
  if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
    webm_free(input.webm_ctx);
1009 1010 1011
#endif

  if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM)
John Koleszar's avatar
John Koleszar committed
1012
    free(buf);
1013

1014 1015
  if (scaled_img) vpx_img_free(scaled_img);

1016 1017 1018 1019 1020
  for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
    free(ext_fb_list.ext_fb[i].data);
  }
  free(ext_fb_list.ext_fb);

John Koleszar's avatar
John Koleszar committed
1021 1022
  fclose(infile);
  free(argv);
John Koleszar's avatar
John Koleszar committed
1023

John Koleszar's avatar
John Koleszar committed
1024
  return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
John Koleszar's avatar
John Koleszar committed
1025
}
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047

int main(int argc, const char **argv_) {
  unsigned int loops = 1, i;
  char **argv, **argi, **argj;
  struct arg arg;
  int error = 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, &looparg, argi)) {
      loops = arg_parse_uint(&arg);
      break;
    }
  }
  free(argv);
  for (i = 0; !error && i < loops; i++)
    error = main_loop(argc, argv_);
  return error;
}