WebM VP8 Codec SDK
vpxdec
1 /*
2  * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3  *
4  * Use of this source code is governed by a BSD-style license
5  * that can be found in the LICENSE file in the root of the source
6  * 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.
9  */
10 
11 
12 /* This is a simple program that reads ivf files and decodes them
13  * using the new interface. Decoded frames are output as YV12 raw.
14  */
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <limits.h>
20 
21 #define VPX_CODEC_DISABLE_COMPAT 1
22 #include "vpx_config.h"
23 #include "vpx/vpx_decoder.h"
24 #include "vpx_ports/vpx_timer.h"
25 #if CONFIG_VP8_DECODER
26 #include "vpx/vp8dx.h"
27 #endif
28 #if CONFIG_MD5
29 #include "md5_utils.h"
30 #endif
31 #include "tools_common.h"
32 #include "nestegg/include/nestegg/nestegg.h"
33 
34 #if CONFIG_OS_SUPPORT
35 #if defined(_MSC_VER)
36 #include <io.h>
37 #define snprintf _snprintf
38 #define isatty _isatty
39 #define fileno _fileno
40 #else
41 #include <unistd.h>
42 #endif
43 #endif
44 
45 #ifndef PATH_MAX
46 #define PATH_MAX 256
47 #endif
48 
49 static const char *exec_name;
50 
51 #define VP8_FOURCC (0x00385056)
52 static const struct
53 {
54  char const *name;
55  vpx_codec_iface_t *iface;
56  unsigned int fourcc;
57  unsigned int fourcc_mask;
58 } ifaces[] =
59 {
60 #if CONFIG_VP8_DECODER
61  {"vp8", &vpx_codec_vp8_dx_algo, VP8_FOURCC, 0x00FFFFFF},
62 #endif
63 };
64 
65 #include "args.h"
66 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
67  "Codec to use");
68 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
69  "Output raw YV12 frames");
70 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
71  "Output raw I420 frames");
72 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
73  "Flip the chroma planes in the output");
74 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
75  "Don't process the decoded frames");
76 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
77  "Show progress after each frame decodes");
78 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
79  "Stop decoding after n frames");
80 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
81  "Postprocess decoded frames");
82 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
83  "Show timing summary");
84 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
85  "Output file name pattern (see below)");
86 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
87  "Max threads to use");
88 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0,
89  "Show version string");
90 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0,
91  "Enable decoder error-concealment");
92 
93 
94 #if CONFIG_MD5
95 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
96  "Compute the MD5 sum of the decoded frame");
97 #endif
98 static const arg_def_t *all_args[] =
99 {
100  &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
101  &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile,
102  &threadsarg, &verbosearg,
103 #if CONFIG_MD5
104  &md5arg,
105 #endif
106  &error_concealment,
107  NULL
108 };
109 
110 #if CONFIG_VP8_DECODER
111 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
112  "Enable VP8 postproc add noise");
113 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
114  "Enable VP8 deblocking");
115 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
116  "Enable VP8 demacroblocking, w/ level");
117 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
118  "Enable VP8 visible debug info");
119 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1,
120  "Display only selected reference frame per macro block");
121 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1,
122  "Display only selected macro block modes");
123 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1,
124  "Display only selected block modes");
125 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1,
126  "Draw only selected motion vectors");
127 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0,
128  "Enable multiframe quality enhancement");
129 
130 static const arg_def_t *vp8_pp_args[] =
131 {
132  &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
133  &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe,
134  NULL
135 };
136 #endif
137 
138 static void usage_exit()
139 {
140  int i;
141 
142  fprintf(stderr, "Usage: %s <options> filename\n\n"
143  "Options:\n", exec_name);
144  arg_show_usage(stderr, all_args);
145 #if CONFIG_VP8_DECODER
146  fprintf(stderr, "\nVP8 Postprocessing Options:\n");
147  arg_show_usage(stderr, vp8_pp_args);
148 #endif
149  fprintf(stderr,
150  "\nOutput File Patterns:\n\n"
151  " The -o argument specifies the name of the file(s) to "
152  "write to. If the\n argument does not include any escape "
153  "characters, the output will be\n written to a single file. "
154  "Otherwise, the filename will be calculated by\n expanding "
155  "the following escape characters:\n");
156  fprintf(stderr,
157  "\n\t%%w - Frame width"
158  "\n\t%%h - Frame height"
159  "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"
160  "\n\n Pattern arguments are only supported in conjunction "
161  "with the --yv12 and\n --i420 options. If the -o option is "
162  "not specified, the output will be\n directed to stdout.\n"
163  );
164  fprintf(stderr, "\nIncluded decoders:\n\n");
165 
166  for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
167  fprintf(stderr, " %-6s - %s\n",
168  ifaces[i].name,
169  vpx_codec_iface_name(ifaces[i].iface));
170 
171  exit(EXIT_FAILURE);
172 }
173 
174 void die(const char *fmt, ...)
175 {
176  va_list ap;
177  va_start(ap, fmt);
178  vfprintf(stderr, fmt, ap);
179  fprintf(stderr, "\n");
180  usage_exit();
181 }
182 
183 static unsigned int mem_get_le16(const void *vmem)
184 {
185  unsigned int val;
186  const unsigned char *mem = (const unsigned char *)vmem;
187 
188  val = mem[1] << 8;
189  val |= mem[0];
190  return val;
191 }
192 
193 static unsigned int mem_get_le32(const void *vmem)
194 {
195  unsigned int val;
196  const unsigned char *mem = (const unsigned char *)vmem;
197 
198  val = mem[3] << 24;
199  val |= mem[2] << 16;
200  val |= mem[1] << 8;
201  val |= mem[0];
202  return val;
203 }
204 
205 enum file_kind
206 {
207  RAW_FILE,
208  IVF_FILE,
209  WEBM_FILE
210 };
211 
212 struct input_ctx
213 {
214  enum file_kind kind;
215  FILE *infile;
216  nestegg *nestegg_ctx;
217  nestegg_packet *pkt;
218  unsigned int chunk;
219  unsigned int chunks;
220  unsigned int video_track;
221 };
222 
223 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
224 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
225 static int read_frame(struct input_ctx *input,
226  uint8_t **buf,
227  size_t *buf_sz,
228  size_t *buf_alloc_sz)
229 {
230  char raw_hdr[IVF_FRAME_HDR_SZ];
231  size_t new_buf_sz;
232  FILE *infile = input->infile;
233  enum file_kind kind = input->kind;
234  if(kind == WEBM_FILE)
235  {
236  if(input->chunk >= input->chunks)
237  {
238  unsigned int track;
239 
240  do
241  {
242  /* End of this packet, get another. */
243  if(input->pkt)
244  nestegg_free_packet(input->pkt);
245 
246  if(nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0
247  || nestegg_packet_track(input->pkt, &track))
248  return 1;
249 
250  } while(track != input->video_track);
251 
252  if(nestegg_packet_count(input->pkt, &input->chunks))
253  return 1;
254  input->chunk = 0;
255  }
256 
257  if(nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz))
258  return 1;
259  input->chunk++;
260 
261  return 0;
262  }
263  /* For both the raw and ivf formats, the frame size is the first 4 bytes
264  * of the frame header. We just need to special case on the header
265  * size.
266  */
267  else if (fread(raw_hdr, kind==IVF_FILE
268  ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1)
269  {
270  if (!feof(infile))
271  fprintf(stderr, "Failed to read frame size\n");
272 
273  new_buf_sz = 0;
274  }
275  else
276  {
277  new_buf_sz = mem_get_le32(raw_hdr);
278 
279  if (new_buf_sz > 256 * 1024 * 1024)
280  {
281  fprintf(stderr, "Error: Read invalid frame size (%u)\n",
282  (unsigned int)new_buf_sz);
283  new_buf_sz = 0;
284  }
285 
286  if (kind == RAW_FILE && new_buf_sz > 256 * 1024)
287  fprintf(stderr, "Warning: Read invalid frame size (%u)"
288  " - not a raw file?\n", (unsigned int)new_buf_sz);
289 
290  if (new_buf_sz > *buf_alloc_sz)
291  {
292  uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
293 
294  if (new_buf)
295  {
296  *buf = new_buf;
297  *buf_alloc_sz = 2 * new_buf_sz;
298  }
299  else
300  {
301  fprintf(stderr, "Failed to allocate compressed data buffer\n");
302  new_buf_sz = 0;
303  }
304  }
305  }
306 
307  *buf_sz = new_buf_sz;
308 
309  if (!feof(infile))
310  {
311  if (fread(*buf, 1, *buf_sz, infile) != *buf_sz)
312  {
313  fprintf(stderr, "Failed to read full frame\n");
314  return 1;
315  }
316 
317  return 0;
318  }
319 
320  return 1;
321 }
322 
323 void *out_open(const char *out_fn, int do_md5)
324 {
325  void *out = NULL;
326 
327  if (do_md5)
328  {
329 #if CONFIG_MD5
330  MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
331  (void)out_fn;
332  MD5Init(md5_ctx);
333 #endif
334  }
335  else
336  {
337  FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb")
338  : set_binary_mode(stdout);
339 
340  if (!outfile)
341  {
342  fprintf(stderr, "Failed to output file");
343  exit(EXIT_FAILURE);
344  }
345  }
346 
347  return out;
348 }
349 
350 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5)
351 {
352  if (do_md5)
353  {
354 #if CONFIG_MD5
355  MD5Update(out, buf, len);
356 #endif
357  }
358  else
359  {
360  (void) fwrite(buf, 1, len, out);
361  }
362 }
363 
364 void out_close(void *out, const char *out_fn, int do_md5)
365 {
366  if (do_md5)
367  {
368 #if CONFIG_MD5
369  uint8_t md5[16];
370  int i;
371 
372  MD5Final(md5, out);
373  free(out);
374 
375  for (i = 0; i < 16; i++)
376  printf("%02x", md5[i]);
377 
378  printf(" %s\n", out_fn);
379 #endif
380  }
381  else
382  {
383  fclose(out);
384  }
385 }
386 
387 unsigned int file_is_ivf(FILE *infile,
388  unsigned int *fourcc,
389  unsigned int *width,
390  unsigned int *height,
391  unsigned int *fps_den,
392  unsigned int *fps_num)
393 {
394  char raw_hdr[32];
395  int is_ivf = 0;
396 
397  if (fread(raw_hdr, 1, 32, infile) == 32)
398  {
399  if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
400  && raw_hdr[2] == 'I' && raw_hdr[3] == 'F')
401  {
402  is_ivf = 1;
403 
404  if (mem_get_le16(raw_hdr + 4) != 0)
405  fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
406  " decode properly.");
407 
408  *fourcc = mem_get_le32(raw_hdr + 8);
409  *width = mem_get_le16(raw_hdr + 12);
410  *height = mem_get_le16(raw_hdr + 14);
411  *fps_num = mem_get_le32(raw_hdr + 16);
412  *fps_den = mem_get_le32(raw_hdr + 20);
413 
414  /* Some versions of vpxenc used 1/(2*fps) for the timebase, so
415  * we can guess the framerate using only the timebase in this
416  * case. Other files would require reading ahead to guess the
417  * timebase, like we do for webm.
418  */
419  if(*fps_num < 1000)
420  {
421  /* Correct for the factor of 2 applied to the timebase in the
422  * encoder.
423  */
424  if(*fps_num&1)*fps_den<<=1;
425  else *fps_num>>=1;
426  }
427  else
428  {
429  /* Don't know FPS for sure, and don't have readahead code
430  * (yet?), so just default to 30fps.
431  */
432  *fps_num = 30;
433  *fps_den = 1;
434  }
435  }
436  }
437 
438  if (!is_ivf)
439  rewind(infile);
440 
441  return is_ivf;
442 }
443 
444 
445 unsigned int file_is_raw(FILE *infile,
446  unsigned int *fourcc,
447  unsigned int *width,
448  unsigned int *height,
449  unsigned int *fps_den,
450  unsigned int *fps_num)
451 {
452  unsigned char buf[32];
453  int is_raw = 0;
455 
456  si.sz = sizeof(si);
457 
458  if (fread(buf, 1, 32, infile) == 32)
459  {
460  int i;
461 
462  if(mem_get_le32(buf) < 256 * 1024 * 1024)
463  for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
464  if(!vpx_codec_peek_stream_info(ifaces[i].iface,
465  buf + 4, 32 - 4, &si))
466  {
467  is_raw = 1;
468  *fourcc = ifaces[i].fourcc;
469  *width = si.w;
470  *height = si.h;
471  *fps_num = 30;
472  *fps_den = 1;
473  break;
474  }
475  }
476 
477  rewind(infile);
478  return is_raw;
479 }
480 
481 
482 static int
483 nestegg_read_cb(void *buffer, size_t length, void *userdata)
484 {
485  FILE *f = userdata;
486 
487  if(fread(buffer, 1, length, f) < length)
488  {
489  if (ferror(f))
490  return -1;
491  if (feof(f))
492  return 0;
493  }
494  return 1;
495 }
496 
497 
498 static int
499 nestegg_seek_cb(int64_t offset, int whence, void * userdata)
500 {
501  switch(whence) {
502  case NESTEGG_SEEK_SET: whence = SEEK_SET; break;
503  case NESTEGG_SEEK_CUR: whence = SEEK_CUR; break;
504  case NESTEGG_SEEK_END: whence = SEEK_END; break;
505  };
506  return fseek(userdata, (long)offset, whence)? -1 : 0;
507 }
508 
509 
510 static int64_t
511 nestegg_tell_cb(void * userdata)
512 {
513  return ftell(userdata);
514 }
515 
516 
517 static void
518 nestegg_log_cb(nestegg * context, unsigned int severity, char const * format,
519  ...)
520 {
521  va_list ap;
522 
523  va_start(ap, format);
524  vfprintf(stderr, format, ap);
525  fprintf(stderr, "\n");
526  va_end(ap);
527 }
528 
529 
530 static int
531 webm_guess_framerate(struct input_ctx *input,
532  unsigned int *fps_den,
533  unsigned int *fps_num)
534 {
535  unsigned int i;
536  uint64_t tstamp=0;
537 
538  /* Guess the framerate. Read up to 1 second, or 50 video packets,
539  * whichever comes first.
540  */
541  for(i=0; tstamp < 1000000000 && i < 50;)
542  {
543  nestegg_packet * pkt;
544  unsigned int track;
545 
546  if(nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0)
547  break;
548 
549  nestegg_packet_track(pkt, &track);
550  if(track == input->video_track)
551  {
552  nestegg_packet_tstamp(pkt, &tstamp);
553  i++;
554  }
555 
556  nestegg_free_packet(pkt);
557  }
558 
559  if(nestegg_track_seek(input->nestegg_ctx, input->video_track, 0))
560  goto fail;
561 
562  *fps_num = (i - 1) * 1000000;
563  *fps_den = (unsigned int)(tstamp / 1000);
564  return 0;
565 fail:
566  nestegg_destroy(input->nestegg_ctx);
567  input->nestegg_ctx = NULL;
568  rewind(input->infile);
569  return 1;
570 }
571 
572 
573 static int
574 file_is_webm(struct input_ctx *input,
575  unsigned int *fourcc,
576  unsigned int *width,
577  unsigned int *height,
578  unsigned int *fps_den,
579  unsigned int *fps_num)
580 {
581  unsigned int i, n;
582  int track_type = -1;
583 
584  nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
585  nestegg_video_params params;
586 
587  io.userdata = input->infile;
588  if(nestegg_init(&input->nestegg_ctx, io, NULL))
589  goto fail;
590 
591  if(nestegg_track_count(input->nestegg_ctx, &n))
592  goto fail;
593 
594  for(i=0; i<n; i++)
595  {
596  track_type = nestegg_track_type(input->nestegg_ctx, i);
597 
598  if(track_type == NESTEGG_TRACK_VIDEO)
599  break;
600  else if(track_type < 0)
601  goto fail;
602  }
603 
604  if(nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8)
605  {
606  fprintf(stderr, "Not VP8 video, quitting.\n");
607  exit(1);
608  }
609 
610  input->video_track = i;
611 
612  if(nestegg_track_video_params(input->nestegg_ctx, i, &params))
613  goto fail;
614 
615  *fps_den = 0;
616  *fps_num = 0;
617  *fourcc = VP8_FOURCC;
618  *width = params.width;
619  *height = params.height;
620  return 1;
621 fail:
622  input->nestegg_ctx = NULL;
623  rewind(input->infile);
624  return 0;
625 }
626 
627 
628 void show_progress(int frame_in, int frame_out, unsigned long dx_time)
629 {
630  fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r",
631  frame_in, frame_out, dx_time,
632  (float)frame_out * 1000000.0 / (float)dx_time);
633 }
634 
635 
636 void generate_filename(const char *pattern, char *out, size_t q_len,
637  unsigned int d_w, unsigned int d_h,
638  unsigned int frame_in)
639 {
640  const char *p = pattern;
641  char *q = out;
642 
643  do
644  {
645  char *next_pat = strchr(p, '%');
646 
647  if(p == next_pat)
648  {
649  size_t pat_len;
650 
651  /* parse the pattern */
652  q[q_len - 1] = '\0';
653  switch(p[1])
654  {
655  case 'w': snprintf(q, q_len - 1, "%d", d_w); break;
656  case 'h': snprintf(q, q_len - 1, "%d", d_h); break;
657  case '1': snprintf(q, q_len - 1, "%d", frame_in); break;
658  case '2': snprintf(q, q_len - 1, "%02d", frame_in); break;
659  case '3': snprintf(q, q_len - 1, "%03d", frame_in); break;
660  case '4': snprintf(q, q_len - 1, "%04d", frame_in); break;
661  case '5': snprintf(q, q_len - 1, "%05d", frame_in); break;
662  case '6': snprintf(q, q_len - 1, "%06d", frame_in); break;
663  case '7': snprintf(q, q_len - 1, "%07d", frame_in); break;
664  case '8': snprintf(q, q_len - 1, "%08d", frame_in); break;
665  case '9': snprintf(q, q_len - 1, "%09d", frame_in); break;
666  default:
667  die("Unrecognized pattern %%%c\n", p[1]);
668  }
669 
670  pat_len = strlen(q);
671  if(pat_len >= q_len - 1)
672  die("Output filename too long.\n");
673  q += pat_len;
674  p += 2;
675  q_len -= pat_len;
676  }
677  else
678  {
679  size_t copy_len;
680 
681  /* copy the next segment */
682  if(!next_pat)
683  copy_len = strlen(p);
684  else
685  copy_len = next_pat - p;
686 
687  if(copy_len >= q_len - 1)
688  die("Output filename too long.\n");
689 
690  memcpy(q, p, copy_len);
691  q[copy_len] = '\0';
692  q += copy_len;
693  p += copy_len;
694  q_len -= copy_len;
695  }
696  } while(*p);
697 }
698 
699 
700 int main(int argc, const char **argv_)
701 {
702  vpx_codec_ctx_t decoder;
703  char *fn = NULL;
704  int i;
705  uint8_t *buf = NULL;
706  size_t buf_sz = 0, buf_alloc_sz = 0;
707  FILE *infile;
708  int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
709  int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
710  int ec_enabled = 0;
711  vpx_codec_iface_t *iface = NULL;
712  unsigned int fourcc;
713  unsigned long dx_time = 0;
714  struct arg arg;
715  char **argv, **argi, **argj;
716  const char *outfile_pattern = 0;
717  char outfile[PATH_MAX];
718  int single_file;
719  int use_y4m = 1;
720  unsigned int width;
721  unsigned int height;
722  unsigned int fps_den;
723  unsigned int fps_num;
724  void *out = NULL;
725  vpx_codec_dec_cfg_t cfg = {0};
726 #if CONFIG_VP8_DECODER
727  vp8_postproc_cfg_t vp8_pp_cfg = {0};
728  int vp8_dbg_color_ref_frame = 0;
729  int vp8_dbg_color_mb_modes = 0;
730  int vp8_dbg_color_b_modes = 0;
731  int vp8_dbg_display_mv = 0;
732 #endif
733  struct input_ctx input = {0};
734  int frames_corrupted = 0;
735  int dec_flags = 0;
736 
737  /* Parse command line */
738  exec_name = argv_[0];
739  argv = argv_dup(argc - 1, argv_ + 1);
740 
741  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
742  {
743  memset(&arg, 0, sizeof(arg));
744  arg.argv_step = 1;
745 
746  if (arg_match(&arg, &codecarg, argi))
747  {
748  int j, k = -1;
749 
750  for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
751  if (!strcmp(ifaces[j].name, arg.val))
752  k = j;
753 
754  if (k >= 0)
755  iface = ifaces[k].iface;
756  else
757  die("Error: Unrecognized argument (%s) to --codec\n",
758  arg.val);
759  }
760  else if (arg_match(&arg, &outputfile, argi))
761  outfile_pattern = arg.val;
762  else if (arg_match(&arg, &use_yv12, argi))
763  {
764  use_y4m = 0;
765  flipuv = 1;
766  }
767  else if (arg_match(&arg, &use_i420, argi))
768  {
769  use_y4m = 0;
770  flipuv = 0;
771  }
772  else if (arg_match(&arg, &flipuvarg, argi))
773  flipuv = 1;
774  else if (arg_match(&arg, &noblitarg, argi))
775  noblit = 1;
776  else if (arg_match(&arg, &progressarg, argi))
777  progress = 1;
778  else if (arg_match(&arg, &limitarg, argi))
779  stop_after = arg_parse_uint(&arg);
780  else if (arg_match(&arg, &postprocarg, argi))
781  postproc = 1;
782  else if (arg_match(&arg, &md5arg, argi))
783  do_md5 = 1;
784  else if (arg_match(&arg, &summaryarg, argi))
785  summary = 1;
786  else if (arg_match(&arg, &threadsarg, argi))
787  cfg.threads = arg_parse_uint(&arg);
788  else if (arg_match(&arg, &verbosearg, argi))
789  quiet = 0;
790 
791 #if CONFIG_VP8_DECODER
792  else if (arg_match(&arg, &addnoise_level, argi))
793  {
794  postproc = 1;
795  vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
796  vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
797  }
798  else if (arg_match(&arg, &demacroblock_level, argi))
799  {
800  postproc = 1;
801  vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
802  vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
803  }
804  else if (arg_match(&arg, &deblock, argi))
805  {
806  postproc = 1;
807  vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
808  }
809  else if (arg_match(&arg, &mfqe, argi))
810  {
811  postproc = 1;
812  vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
813  }
814  else if (arg_match(&arg, &pp_debug_info, argi))
815  {
816  unsigned int level = arg_parse_uint(&arg);
817 
818  postproc = 1;
819  vp8_pp_cfg.post_proc_flag &= ~0x7;
820 
821  if (level)
822  vp8_pp_cfg.post_proc_flag |= level;
823  }
824  else if (arg_match(&arg, &pp_disp_ref_frame, argi))
825  {
826  unsigned int flags = arg_parse_int(&arg);
827  if (flags)
828  {
829  postproc = 1;
830  vp8_dbg_color_ref_frame = flags;
831  }
832  }
833  else if (arg_match(&arg, &pp_disp_mb_modes, argi))
834  {
835  unsigned int flags = arg_parse_int(&arg);
836  if (flags)
837  {
838  postproc = 1;
839  vp8_dbg_color_mb_modes = flags;
840  }
841  }
842  else if (arg_match(&arg, &pp_disp_b_modes, argi))
843  {
844  unsigned int flags = arg_parse_int(&arg);
845  if (flags)
846  {
847  postproc = 1;
848  vp8_dbg_color_b_modes = flags;
849  }
850  }
851  else if (arg_match(&arg, &pp_disp_mvs, argi))
852  {
853  unsigned int flags = arg_parse_int(&arg);
854  if (flags)
855  {
856  postproc = 1;
857  vp8_dbg_display_mv = flags;
858  }
859  }
860  else if (arg_match(&arg, &error_concealment, argi))
861  {
862  ec_enabled = 1;
863  }
864 
865 #endif
866  else
867  argj++;
868  }
869 
870  /* Check for unrecognized options */
871  for (argi = argv; *argi; argi++)
872  if (argi[0][0] == '-' && strlen(argi[0]) > 1)
873  die("Error: Unrecognized option %s\n", *argi);
874 
875  /* Handle non-option arguments */
876  fn = argv[0];
877 
878  if (!fn)
879  usage_exit();
880 
881  /* Open file */
882  infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
883 
884  if (!infile)
885  {
886  fprintf(stderr, "Failed to open file '%s'",
887  strcmp(fn, "-") ? fn : "stdin");
888  return EXIT_FAILURE;
889  }
890 #if CONFIG_OS_SUPPORT
891  /* Make sure we don't dump to the terminal, unless forced to with -o - */
892  if(!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit)
893  {
894  fprintf(stderr,
895  "Not dumping raw video to your terminal. Use '-o -' to "
896  "override.\n");
897  return EXIT_FAILURE;
898  }
899 #endif
900  input.infile = infile;
901  if(file_is_ivf(infile, &fourcc, &width, &height, &fps_den,
902  &fps_num))
903  input.kind = IVF_FILE;
904  else if(file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num))
905  input.kind = WEBM_FILE;
906  else if(file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num))
907  input.kind = RAW_FILE;
908  else
909  {
910  fprintf(stderr, "Unrecognized input file type.\n");
911  return EXIT_FAILURE;
912  }
913 
914  /* If the output file is not set or doesn't have a sequence number in
915  * it, then we only open it once.
916  */
917  outfile_pattern = outfile_pattern ? outfile_pattern : "-";
918  single_file = 1;
919  {
920  const char *p = outfile_pattern;
921  do
922  {
923  p = strchr(p, '%');
924  if(p && p[1] >= '1' && p[1] <= '9')
925  {
926  /* pattern contains sequence number, so it's not unique. */
927  single_file = 0;
928  break;
929  }
930  if(p)
931  p++;
932  } while(p);
933  }
934 
935  if(single_file && !noblit)
936  {
937  generate_filename(outfile_pattern, outfile, sizeof(outfile)-1,
938  width, height, 0);
939  out = out_open(outfile, do_md5);
940  }
941 
942  if (use_y4m && !noblit)
943  {
944  char buffer[128];
945  if (!single_file)
946  {
947  fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
948  " try --i420 or --yv12.\n");
949  return EXIT_FAILURE;
950  }
951 
952  if(input.kind == WEBM_FILE)
953  if(webm_guess_framerate(&input, &fps_den, &fps_num))
954  {
955  fprintf(stderr, "Failed to guess framerate -- error parsing "
956  "webm file?\n");
957  return EXIT_FAILURE;
958  }
959 
960 
961  /*Note: We can't output an aspect ratio here because IVF doesn't
962  store one, and neither does VP8.
963  That will have to wait until these tools support WebM natively.*/
964  sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n",
965  "420jpeg", width, height, fps_num, fps_den, 'p');
966  out_put(out, (unsigned char *)buffer,
967  (unsigned int)strlen(buffer), do_md5);
968  }
969 
970  /* Try to determine the codec from the fourcc. */
971  for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
972  if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc)
973  {
974  vpx_codec_iface_t *ivf_iface = ifaces[i].iface;
975 
976  if (iface && iface != ivf_iface)
977  fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
978  ifaces[i].name);
979  else
980  iface = ivf_iface;
981 
982  break;
983  }
984 
985  dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
986  (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
987  if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg,
988  dec_flags))
989  {
990  fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder));
991  return EXIT_FAILURE;
992  }
993 
994  if (!quiet)
995  fprintf(stderr, "%s\n", decoder.name);
996 
997 #if CONFIG_VP8_DECODER
998 
999  if (vp8_pp_cfg.post_proc_flag
1000  && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg))
1001  {
1002  fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
1003  return EXIT_FAILURE;
1004  }
1005 
1006  if (vp8_dbg_color_ref_frame
1007  && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame))
1008  {
1009  fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
1010  return EXIT_FAILURE;
1011  }
1012 
1013  if (vp8_dbg_color_mb_modes
1014  && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes))
1015  {
1016  fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
1017  return EXIT_FAILURE;
1018  }
1019 
1020  if (vp8_dbg_color_b_modes
1021  && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes))
1022  {
1023  fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
1024  return EXIT_FAILURE;
1025  }
1026 
1027  if (vp8_dbg_display_mv
1028  && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv))
1029  {
1030  fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
1031  return EXIT_FAILURE;
1032  }
1033 #endif
1034 
1035  /* Decode file */
1036  while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz))
1037  {
1038  vpx_codec_iter_t iter = NULL;
1039  vpx_image_t *img;
1040  struct vpx_usec_timer timer;
1041  int corrupted;
1042 
1043  vpx_usec_timer_start(&timer);
1044 
1045  if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0))
1046  {
1047  const char *detail = vpx_codec_error_detail(&decoder);
1048  fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder));
1049 
1050  if (detail)
1051  fprintf(stderr, " Additional information: %s\n", detail);
1052 
1053  goto fail;
1054  }
1055 
1056  vpx_usec_timer_mark(&timer);
1057  dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
1058 
1059  ++frame_in;
1060 
1061  if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted))
1062  {
1063  fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n",
1064  vpx_codec_error(&decoder));
1065  goto fail;
1066  }
1067  frames_corrupted += corrupted;
1068 
1069  vpx_usec_timer_start(&timer);
1070 
1071  if ((img = vpx_codec_get_frame(&decoder, &iter)))
1072  ++frame_out;
1073 
1074  vpx_usec_timer_mark(&timer);
1075  dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
1076 
1077  if (progress)
1078  show_progress(frame_in, frame_out, dx_time);
1079 
1080  if (!noblit)
1081  {
1082  if (img)
1083  {
1084  unsigned int y;
1085  char out_fn[PATH_MAX];
1086  uint8_t *buf;
1087 
1088  if (!single_file)
1089  {
1090  size_t len = sizeof(out_fn)-1;
1091 
1092  out_fn[len] = '\0';
1093  generate_filename(outfile_pattern, out_fn, len-1,
1094  img->d_w, img->d_h, frame_in);
1095  out = out_open(out_fn, do_md5);
1096  }
1097  else if(use_y4m)
1098  out_put(out, (unsigned char *)"FRAME\n", 6, do_md5);
1099 
1100  buf = img->planes[VPX_PLANE_Y];
1101 
1102  for (y = 0; y < img->d_h; y++)
1103  {
1104  out_put(out, buf, img->d_w, do_md5);
1105  buf += img->stride[VPX_PLANE_Y];
1106  }
1107 
1108  buf = img->planes[flipuv?VPX_PLANE_V:VPX_PLANE_U];
1109 
1110  for (y = 0; y < (1 + img->d_h) / 2; y++)
1111  {
1112  out_put(out, buf, (1 + img->d_w) / 2, do_md5);
1113  buf += img->stride[VPX_PLANE_U];
1114  }
1115 
1116  buf = img->planes[flipuv?VPX_PLANE_U:VPX_PLANE_V];
1117 
1118  for (y = 0; y < (1 + img->d_h) / 2; y++)
1119  {
1120  out_put(out, buf, (1 + img->d_w) / 2, do_md5);
1121  buf += img->stride[VPX_PLANE_V];
1122  }
1123 
1124  if (!single_file)
1125  out_close(out, out_fn, do_md5);
1126  }
1127  }
1128 
1129  if (stop_after && frame_in >= stop_after)
1130  break;
1131  }
1132 
1133  if (summary || progress)
1134  {
1135  show_progress(frame_in, frame_out, dx_time);
1136  fprintf(stderr, "\n");
1137  }
1138 
1139  if (frames_corrupted)
1140  fprintf(stderr, "WARNING: %d frames corrupted.\n",frames_corrupted);
1141 
1142 fail:
1143 
1144  if (vpx_codec_destroy(&decoder))
1145  {
1146  fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
1147  return EXIT_FAILURE;
1148  }
1149 
1150  if (single_file && !noblit)
1151  out_close(out, outfile, do_md5);
1152 
1153  if(input.nestegg_ctx)
1154  nestegg_destroy(input.nestegg_ctx);
1155  if(input.kind != WEBM_FILE)
1156  free(buf);
1157  fclose(infile);
1158  free(argv);
1159 
1160  return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
1161 }