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