/* * 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. Load more
/* * 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_HIGHBITDEPTH static const arg_def_t outbitdeptharg = ARG_DEF(NULL, "output-bit-depth", 1, "Output bit-depth for decoded frames"); #endif static 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_DECODER static 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_LIBYUV static 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); } #endif static 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;