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