1125 lines · 36.5 KB · C
RawDownload
/* *  Copyright (c) 2010 The WebM project authors. All Rights Reserved. * *  Use of this source code is governed by a BSD-style license *  that can be found in the LICENSE file in the root of the source *  tree. An additional intellectual property rights grant can be found *  in the file PATENTS.  All contributing project authors may *  be found in the AUTHORS file in the root of the source tree. */ #include <assert.h>#include <limits.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h> #include "./vpx_config.h" #if CONFIG_LIBYUV#include "third_party/libyuv/include/libyuv/scale.h"#endif #include "./args.h"#include "./ivfdec.h" #include "vpx/vpx_decoder.h"#include "vpx_ports/mem_ops.h"#include "vpx_ports/vpx_timer.h" #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER#include "vpx/vp8dx.h"#endif #include "./md5_utils.h" #include "./tools_common.h"#if CONFIG_WEBM_IO#include "./webmdec.h"#endif#include "./y4menc.h" static const char *exec_name; struct VpxDecInputContext {  struct VpxInputContext *vpx_input_ctx;  struct WebmInputContext *webm_ctx;}; static const arg_def_t help =    ARG_DEF(NULL, "help", 0, "Show usage options and exit");static const arg_def_t looparg =    ARG_DEF(NULL, "loops", 1, "Number of times to decode the file");static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, "Codec to use");static const arg_def_t use_yv12 =    ARG_DEF(NULL, "yv12", 0, "Output raw YV12 frames");static const arg_def_t use_i420 =    ARG_DEF(NULL, "i420", 0, "Output raw I420 frames");static const arg_def_t flipuvarg =    ARG_DEF(NULL, "flipuv", 0, "Flip the chroma planes in the output");static const arg_def_t rawvideo =    ARG_DEF(NULL, "rawvideo", 0, "Output raw YUV frames");static const arg_def_t noblitarg =    ARG_DEF(NULL, "noblit", 0, "Don't process the decoded frames");static const arg_def_t progressarg =    ARG_DEF(NULL, "progress", 0, "Show progress after each frame decodes");static const arg_def_t limitarg =    ARG_DEF(NULL, "limit", 1, "Stop decoding after n frames");static const arg_def_t skiparg =    ARG_DEF(NULL, "skip", 1, "Skip the first n input frames");static const arg_def_t postprocarg =    ARG_DEF(NULL, "postproc", 0, "Postprocess decoded frames");static const arg_def_t summaryarg =    ARG_DEF(NULL, "summary", 0, "Show timing summary");static const arg_def_t outputfile =    ARG_DEF("o", "output", 1, "Output file name pattern (see below)");static const arg_def_t threadsarg =    ARG_DEF("t", "threads", 1, "Max threads to use");static const arg_def_t frameparallelarg =    ARG_DEF(NULL, "frame-parallel", 0, "Frame parallel decode (ignored)");static const arg_def_t verbosearg =    ARG_DEF("v", "verbose", 0, "Show version string");static const arg_def_t error_concealment =    ARG_DEF(NULL, "error-concealment", 0, "Enable decoder error-concealment");static const arg_def_t scalearg =    ARG_DEF("S", "scale", 0, "Scale output frames uniformly");static const arg_def_t continuearg =    ARG_DEF("k", "keep-going", 0, "(debug) Continue decoding after error");static const arg_def_t fb_arg =    ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use");static const arg_def_t md5arg =    ARG_DEF(NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");#if CONFIG_VP9_HIGHBITDEPTHstatic const arg_def_t outbitdeptharg =    ARG_DEF(NULL, "output-bit-depth", 1, "Output bit-depth for decoded frames");#endifstatic const arg_def_t svcdecodingarg = ARG_DEF(    NULL, "svc-decode-layer", 1, "Decode SVC stream up to given spatial layer");static const arg_def_t framestatsarg =    ARG_DEF(NULL, "framestats", 1, "Output per-frame stats (.csv format)");static const arg_def_t rowmtarg =    ARG_DEF(NULL, "row-mt", 1, "Enable multi-threading to run row-wise in VP9");static const arg_def_t lpfoptarg =    ARG_DEF(NULL, "lpf-opt", 1,            "Do loopfilter without waiting for all threads to sync."); static const arg_def_t *all_args[] = { &help,                                       &codecarg,                                       &use_yv12,                                       &use_i420,                                       &flipuvarg,                                       &rawvideo,                                       &noblitarg,                                       &progressarg,                                       &limitarg,                                       &skiparg,                                       &postprocarg,                                       &summaryarg,                                       &outputfile,                                       &threadsarg,                                       &frameparallelarg,                                       &verbosearg,                                       &scalearg,                                       &fb_arg,                                       &md5arg,                                       &error_concealment,                                       &continuearg,#if CONFIG_VP9_HIGHBITDEPTH                                       &outbitdeptharg,#endif                                       &svcdecodingarg,                                       &framestatsarg,                                       &rowmtarg,                                       &lpfoptarg,                                       NULL }; #if CONFIG_VP8_DECODERstatic const arg_def_t addnoise_level =    ARG_DEF(NULL, "noise-level", 1, "Enable VP8 postproc add noise");static const arg_def_t deblock =    ARG_DEF(NULL, "deblock", 0, "Enable VP8 deblocking");static const arg_def_t demacroblock_level = ARG_DEF(    NULL, "demacroblock-level", 1, "Enable VP8 demacroblocking, w/ level");static const arg_def_t mfqe =    ARG_DEF(NULL, "mfqe", 0, "Enable multiframe quality enhancement"); static const arg_def_t *vp8_pp_args[] = { &addnoise_level, &deblock,                                          &demacroblock_level, &mfqe, NULL };#endif #if CONFIG_LIBYUVstatic INLINE int libyuv_scale(vpx_image_t *src, vpx_image_t *dst,                               FilterModeEnum mode) {#if CONFIG_VP9_HIGHBITDEPTH  if (src->fmt == VPX_IMG_FMT_I42016) {    assert(dst->fmt == VPX_IMG_FMT_I42016);    return I420Scale_16(        (uint16_t *)src->planes[VPX_PLANE_Y], src->stride[VPX_PLANE_Y] / 2,        (uint16_t *)src->planes[VPX_PLANE_U], src->stride[VPX_PLANE_U] / 2,        (uint16_t *)src->planes[VPX_PLANE_V], src->stride[VPX_PLANE_V] / 2,        src->d_w, src->d_h, (uint16_t *)dst->planes[VPX_PLANE_Y],        dst->stride[VPX_PLANE_Y] / 2, (uint16_t *)dst->planes[VPX_PLANE_U],        dst->stride[VPX_PLANE_U] / 2, (uint16_t *)dst->planes[VPX_PLANE_V],        dst->stride[VPX_PLANE_V] / 2, dst->d_w, dst->d_h, mode);  }#endif  assert(src->fmt == VPX_IMG_FMT_I420);  assert(dst->fmt == VPX_IMG_FMT_I420);  return I420Scale(src->planes[VPX_PLANE_Y], src->stride[VPX_PLANE_Y],                   src->planes[VPX_PLANE_U], src->stride[VPX_PLANE_U],                   src->planes[VPX_PLANE_V], src->stride[VPX_PLANE_V], src->d_w,                   src->d_h, dst->planes[VPX_PLANE_Y], dst->stride[VPX_PLANE_Y],                   dst->planes[VPX_PLANE_U], dst->stride[VPX_PLANE_U],                   dst->planes[VPX_PLANE_V], dst->stride[VPX_PLANE_V], dst->d_w,                   dst->d_h, mode);}#endifstatic void show_help(FILE *fout, int shorthelp) {  int i;   fprintf(fout, "Usage: %s <options> filename\n\n", exec_name);   if (shorthelp) {    fprintf(fout, "Use --help to see the full list of options.\n");    return;  }   fprintf(fout, "Options:\n");  arg_show_usage(fout, all_args);#if CONFIG_VP8_DECODER  fprintf(fout, "\nVP8 Postprocessing Options:\n");  arg_show_usage(fout, vp8_pp_args);#endif  fprintf(fout,          "\nOutput File Patterns:\n\n"          "  The -o argument specifies the name of the file(s) to "          "write to. If the\n  argument does not include any escape "          "characters, the output will be\n  written to a single file. "          "Otherwise, the filename will be calculated by\n  expanding "          "the following escape characters:\n");  fprintf(fout,          "\n\t%%w   - Frame width"          "\n\t%%h   - Frame height"          "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"          "\n\n  Pattern arguments are only supported in conjunction "          "with the --yv12 and\n  --i420 options. If the -o option is "          "not specified, the output will be\n  directed to stdout.\n");  fprintf(fout, "\nIncluded decoders:\n\n");   for (i = 0; i < get_vpx_decoder_count(); ++i) {    const VpxInterface *const decoder = get_vpx_decoder_by_index(i);    fprintf(fout, "    %-6s - %s\n", decoder->name,            vpx_codec_iface_name(decoder->codec_interface()));  }} void usage_exit(void) {  show_help(stderr, 1);  exit(EXIT_FAILURE);} static int raw_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read,                          size_t *buffer_size) {  char raw_hdr[RAW_FRAME_HDR_SZ];  size_t frame_size = 0;   if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) {    if (!feof(infile)) warn("Failed to read RAW frame size\n");  } else {    const size_t kCorruptFrameThreshold = 256 * 1024 * 1024;    const size_t kFrameTooSmallThreshold = 256 * 1024;    frame_size = mem_get_le32(raw_hdr);     if (frame_size > kCorruptFrameThreshold) {      warn("Read invalid frame size (%u)\n", (unsigned int)frame_size);      frame_size = 0;    }     if (frame_size < kFrameTooSmallThreshold) {      warn("Warning: Read invalid frame size (%u) - not a raw file?\n",           (unsigned int)frame_size);    }     if (frame_size > *buffer_size) {      uint8_t *new_buf = realloc(*buffer, 2 * frame_size);      if (new_buf) {        *buffer = new_buf;        *buffer_size = 2 * frame_size;      } else {        warn("Failed to allocate compressed data buffer\n");        frame_size = 0;      }    }  }   if (!feof(infile)) {    if (fread(*buffer, 1, frame_size, infile) != frame_size) {      warn("Failed to read full frame\n");      return 1;    }    *bytes_read = frame_size;    return 0;  }   return 1;} static int dec_read_frame(struct VpxDecInputContext *input, uint8_t **buf,                          size_t *bytes_in_buffer, size_t *buffer_size) {  switch (input->vpx_input_ctx->file_type) {#if CONFIG_WEBM_IO    case FILE_TYPE_WEBM:      return webm_read_frame(input->webm_ctx, buf, bytes_in_buffer);#endif    case FILE_TYPE_RAW:      return raw_read_frame(input->vpx_input_ctx->file, buf, bytes_in_buffer,                            buffer_size);    case FILE_TYPE_IVF:      return ivf_read_frame(input->vpx_input_ctx->file, buf, bytes_in_buffer,                            buffer_size);    default: return 1;  }} static void update_image_md5(const vpx_image_t *img, const int planes[3],                             MD5Context *md5) {  int i, y;   for (i = 0; i < 3; ++i) {    const int plane = planes[i];    const unsigned char *buf = img->planes[plane];    const int stride = img->stride[plane];    const int w = vpx_img_plane_width(img, plane) *                  ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);    const int h = vpx_img_plane_height(img, plane);     for (y = 0; y < h; ++y) {      MD5Update(md5, buf, w);      buf += stride;    }  }} static void write_image_file(const vpx_image_t *img, const int planes[3],                             FILE *file) {  int i, y;#if CONFIG_VP9_HIGHBITDEPTH  const int bytes_per_sample = ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);#else  const int bytes_per_sample = 1;#endif   for (i = 0; i < 3; ++i) {    const int plane = planes[i];    const unsigned char *buf = img->planes[plane];    const int stride = img->stride[plane];    const int w = vpx_img_plane_width(img, plane);    const int h = vpx_img_plane_height(img, plane);     for (y = 0; y < h; ++y) {      fwrite(buf, bytes_per_sample, w, file);      buf += stride;    }  }} static int file_is_raw(struct VpxInputContext *input) {  uint8_t buf[32];  int is_raw = 0;  vpx_codec_stream_info_t si;   si.sz = sizeof(si);   if (fread(buf, 1, 32, input->file) == 32) {    int i;     if (mem_get_le32(buf) < 256 * 1024 * 1024) {      for (i = 0; i < get_vpx_decoder_count(); ++i) {        const VpxInterface *const decoder = get_vpx_decoder_by_index(i);        if (!vpx_codec_peek_stream_info(decoder->codec_interface(), buf + 4,                                        32 - 4, &si)) {          is_raw = 1;          input->fourcc = decoder->fourcc;          input->width = si.w;          input->height = si.h;          input->framerate.numerator = 30;          input->framerate.denominator = 1;          break;        }      }    }  }   rewind(input->file);  return is_raw;} static void show_progress(int frame_in, int frame_out, uint64_t dx_time) {  fprintf(stderr,          "%d decoded frames/%d showed frames in %" PRId64 " us (%.2f fps)\r",          frame_in, frame_out, dx_time,          (double)frame_out * 1000000.0 / (double)dx_time);} struct ExternalFrameBuffer {  uint8_t *data;  size_t size;  int in_use;}; struct ExternalFrameBufferList {  int num_external_frame_buffers;  struct ExternalFrameBuffer *ext_fb;}; // Callback used by libvpx to request an external frame buffer. |cb_priv|// Application private data passed into the set function. |min_size| is the// minimum size in bytes needed to decode the next frame. |fb| pointer to the// frame buffer.static int get_vp9_frame_buffer(void *cb_priv, size_t min_size,                                vpx_codec_frame_buffer_t *fb) {  int i;  struct ExternalFrameBufferList *const ext_fb_list =      (struct ExternalFrameBufferList *)cb_priv;  if (ext_fb_list == NULL) return -1;   // Find a free frame buffer.  for (i = 0; i < ext_fb_list->num_external_frame_buffers; ++i) {    if (!ext_fb_list->ext_fb[i].in_use) break;  }   if (i == ext_fb_list->num_external_frame_buffers) return -1;   if (ext_fb_list->ext_fb[i].size < min_size) {    free(ext_fb_list->ext_fb[i].data);    ext_fb_list->ext_fb[i].data = (uint8_t *)calloc(min_size, sizeof(uint8_t));    if (!ext_fb_list->ext_fb[i].data) return -1;     ext_fb_list->ext_fb[i].size = min_size;  }   fb->data = ext_fb_list->ext_fb[i].data;  fb->size = ext_fb_list->ext_fb[i].size;  ext_fb_list->ext_fb[i].in_use = 1;   // Set the frame buffer's private data to point at the external frame buffer.  fb->priv = &ext_fb_list->ext_fb[i];  return 0;} // Callback used by libvpx when there are no references to the frame buffer.// |cb_priv| user private data passed into the set function. |fb| pointer// to the frame buffer.static int release_vp9_frame_buffer(void *cb_priv,                                    vpx_codec_frame_buffer_t *fb) {  struct ExternalFrameBuffer *const ext_fb =      (struct ExternalFrameBuffer *)fb->priv;  (void)cb_priv;  ext_fb->in_use = 0;  return 0;} static void generate_filename(const char *pattern, char *out, size_t q_len,                              unsigned int d_w, unsigned int d_h,                              unsigned int frame_in) {  const char *p = pattern;  char *q = out;   do {    char *next_pat = strchr(p, '%');     if (p == next_pat) {      size_t pat_len;       /* parse the pattern */      q[q_len - 1] = '\0';      switch (p[1]) {        case 'w': snprintf(q, q_len - 1, "%d", d_w); break;        case 'h': snprintf(q, q_len - 1, "%d", d_h); break;        case '1': snprintf(q, q_len - 1, "%d", frame_in); break;        case '2': snprintf(q, q_len - 1, "%02d", frame_in); break;        case '3': snprintf(q, q_len - 1, "%03d", frame_in); break;        case '4': snprintf(q, q_len - 1, "%04d", frame_in); break;        case '5': snprintf(q, q_len - 1, "%05d", frame_in); break;        case '6': snprintf(q, q_len - 1, "%06d", frame_in); break;        case '7': snprintf(q, q_len - 1, "%07d", frame_in); break;        case '8': snprintf(q, q_len - 1, "%08d", frame_in); break;        case '9': snprintf(q, q_len - 1, "%09d", frame_in); break;        default: die("Unrecognized pattern %%%c\n", p[1]); break;      }       pat_len = strlen(q);      if (pat_len >= q_len - 1) die("Output filename too long.\n");      q += pat_len;      p += 2;      q_len -= pat_len;    } else {      size_t copy_len;       /* copy the next segment */      if (!next_pat)        copy_len = strlen(p);      else        copy_len = next_pat - p;       if (copy_len >= q_len - 1) die("Output filename too long.\n");       memcpy(q, p, copy_len);      q[copy_len] = '\0';      q += copy_len;      p += copy_len;      q_len -= copy_len;    }  } while (*p);} static int is_single_file(const char *outfile_pattern) {  const char *p = outfile_pattern;   do {    p = strchr(p, '%');    if (p && p[1] >= '1' && p[1] <= '9')      return 0;  // pattern contains sequence number, so it's not unique    if (p) p++;  } while (p);   return 1;} static void print_md5(unsigned char digest[16], const char *filename) {  int i;   for (i = 0; i < 16; ++i) printf("%02x", digest[i]);  printf("  %s\n", filename);} static FILE *open_outfile(const char *name) {  if (strcmp("-", name) == 0) {    set_binary_mode(stdout);    return stdout;

Lines 1–500 of 1125.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t