| Index: source/libvpx/vpxdec.c
|
| ===================================================================
|
| --- source/libvpx/vpxdec.c (revision 240950)
|
| +++ source/libvpx/vpxdec.c (working copy)
|
| @@ -8,10 +8,6 @@
|
| * be found in the AUTHORS file in the root of the source tree.
|
| */
|
|
|
| -
|
| -/* This is a simple program that reads ivf files and decodes them
|
| - * using the new interface. Decoded frames are output as YV12 raw.
|
| - */
|
| #include <assert.h>
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
| @@ -19,54 +15,48 @@
|
| #include <string.h>
|
| #include <limits.h>
|
|
|
| +#include "third_party/libyuv/include/libyuv/scale.h"
|
| +
|
| +#include "./args.h"
|
| +#include "./ivfdec.h"
|
| +
|
| #define VPX_CODEC_DISABLE_COMPAT 1
|
| -#include "vpx_config.h"
|
| +#include "./vpx_config.h"
|
| #include "vpx/vpx_decoder.h"
|
| #include "vpx_ports/vpx_timer.h"
|
| +
|
| #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
|
| #include "vpx/vp8dx.h"
|
| #endif
|
| +
|
| #if CONFIG_MD5
|
| -#include "md5_utils.h"
|
| +#include "./md5_utils.h"
|
| #endif
|
| -#include "tools_common.h"
|
| -#include "nestegg/include/nestegg/nestegg.h"
|
| -#include "third_party/libyuv/include/libyuv/scale.h"
|
|
|
| -#if CONFIG_OS_SUPPORT
|
| -#if defined(_MSC_VER)
|
| -#include <io.h>
|
| -#define snprintf _snprintf
|
| -#define isatty _isatty
|
| -#define fileno _fileno
|
| -#else
|
| -#include <unistd.h>
|
| -#endif
|
| -#endif
|
| +#include "./tools_common.h"
|
| +#include "./webmdec.h"
|
|
|
| -#ifndef PATH_MAX
|
| -#define PATH_MAX 256
|
| -#endif
|
| -
|
| static const char *exec_name;
|
|
|
| -#define VP8_FOURCC (0x00385056)
|
| -#define VP9_FOURCC (0x00395056)
|
| static const struct {
|
| char const *name;
|
| const vpx_codec_iface_t *(*iface)(void);
|
| - unsigned int fourcc;
|
| - unsigned int fourcc_mask;
|
| + uint32_t fourcc;
|
| + uint32_t fourcc_mask;
|
| } ifaces[] = {
|
| #if CONFIG_VP8_DECODER
|
| - {"vp8", vpx_codec_vp8_dx, VP8_FOURCC, 0x00FFFFFF},
|
| + {"vp8", vpx_codec_vp8_dx, VP8_FOURCC_MASK, 0x00FFFFFF},
|
| #endif
|
| #if CONFIG_VP9_DECODER
|
| - {"vp9", vpx_codec_vp9_dx, VP9_FOURCC, 0x00FFFFFF},
|
| + {"vp9", vpx_codec_vp9_dx, VP9_FOURCC_MASK, 0x00FFFFFF},
|
| #endif
|
| };
|
|
|
| -#include "args.h"
|
| +struct VpxDecInputContext {
|
| + struct VpxInputContext *vpx_input_ctx;
|
| + struct WebmInputContext *webm_ctx;
|
| +};
|
| +
|
| 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,
|
| @@ -99,6 +89,10 @@
|
| "Enable decoder error-concealment");
|
| static const arg_def_t scalearg = ARG_DEF("S", "scale", 0,
|
| "Scale output frames uniformly");
|
| +static const arg_def_t fb_arg =
|
| + ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use");
|
| +static const arg_def_t fb_lru_arg =
|
| + ARG_DEF(NULL, "frame-buffers-lru", 1, "Turn on/off frame buffer lru");
|
|
|
|
|
| #if CONFIG_MD5
|
| @@ -108,7 +102,7 @@
|
| static const arg_def_t *all_args[] = {
|
| &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
|
| &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
|
| - &threadsarg, &verbosearg, &scalearg,
|
| + &threadsarg, &verbosearg, &scalearg, &fb_arg, &fb_lru_arg,
|
| #if CONFIG_MD5
|
| &md5arg,
|
| #endif
|
| @@ -143,7 +137,7 @@
|
| };
|
| #endif
|
|
|
| -static void usage_exit() {
|
| +void usage_exit() {
|
| int i;
|
|
|
| fprintf(stderr, "Usage: %s <options> filename\n\n"
|
| @@ -178,131 +172,61 @@
|
| exit(EXIT_FAILURE);
|
| }
|
|
|
| -void die(const char *fmt, ...) {
|
| - va_list ap;
|
| - va_start(ap, fmt);
|
| - vfprintf(stderr, fmt, ap);
|
| - fprintf(stderr, "\n");
|
| - usage_exit();
|
| -}
|
| +static int read_frame(struct VpxDecInputContext *input,
|
| + uint8_t **buf,
|
| + size_t *bytes_in_buffer,
|
| + size_t *buffer_size) {
|
| + char raw_hdr[RAW_FRAME_HDR_SZ];
|
| + size_t bytes_to_read = 0;
|
| + FILE *infile = input->vpx_input_ctx->file;
|
| + enum VideoFileType kind = input->vpx_input_ctx->file_type;
|
| + if (kind == FILE_TYPE_WEBM) {
|
| + return webm_read_frame(input->webm_ctx,
|
| + buf, bytes_in_buffer, buffer_size);
|
| + } else if (kind == FILE_TYPE_RAW) {
|
| + if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) {
|
| + if (!feof(infile))
|
| + warn("Failed to read RAW frame size\n");
|
| + } else {
|
| + const int kCorruptFrameThreshold = 256 * 1024 * 1024;
|
| + const int kFrameTooSmallThreshold = 256 * 1024;
|
| + bytes_to_read = mem_get_le32(raw_hdr);
|
|
|
| -static unsigned int mem_get_le16(const void *vmem) {
|
| - unsigned int val;
|
| - const unsigned char *mem = (const unsigned char *)vmem;
|
| + if (bytes_to_read > kCorruptFrameThreshold) {
|
| + warn("Read invalid frame size (%u)\n", (unsigned int)bytes_to_read);
|
| + bytes_to_read = 0;
|
| + }
|
|
|
| - val = mem[1] << 8;
|
| - val |= mem[0];
|
| - return val;
|
| -}
|
| + if (kind == FILE_TYPE_RAW && bytes_to_read < kFrameTooSmallThreshold) {
|
| + warn("Warning: Read invalid frame size (%u) - not a raw file?\n",
|
| + (unsigned int)bytes_to_read);
|
| + }
|
|
|
| -static unsigned int mem_get_le32(const void *vmem) {
|
| - unsigned int val;
|
| - const unsigned char *mem = (const unsigned char *)vmem;
|
| + if (bytes_to_read > *buffer_size) {
|
| + uint8_t *new_buf = realloc(*buf, 2 * bytes_to_read);
|
|
|
| - val = mem[3] << 24;
|
| - val |= mem[2] << 16;
|
| - val |= mem[1] << 8;
|
| - val |= mem[0];
|
| - return val;
|
| -}
|
| -
|
| -enum file_kind {
|
| - RAW_FILE,
|
| - IVF_FILE,
|
| - WEBM_FILE
|
| -};
|
| -
|
| -struct input_ctx {
|
| - enum file_kind kind;
|
| - FILE *infile;
|
| - nestegg *nestegg_ctx;
|
| - nestegg_packet *pkt;
|
| - unsigned int chunk;
|
| - unsigned int chunks;
|
| - unsigned int video_track;
|
| -};
|
| -
|
| -#define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
|
| -#define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
|
| -static int read_frame(struct input_ctx *input,
|
| - uint8_t **buf,
|
| - size_t *buf_sz,
|
| - size_t *buf_alloc_sz) {
|
| - char raw_hdr[IVF_FRAME_HDR_SZ];
|
| - size_t new_buf_sz;
|
| - FILE *infile = input->infile;
|
| - enum file_kind kind = input->kind;
|
| - if (kind == WEBM_FILE) {
|
| - if (input->chunk >= input->chunks) {
|
| - unsigned int track;
|
| -
|
| - do {
|
| - /* End of this packet, get another. */
|
| - if (input->pkt)
|
| - nestegg_free_packet(input->pkt);
|
| -
|
| - if (nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0
|
| - || nestegg_packet_track(input->pkt, &track))
|
| - return 1;
|
| -
|
| - } while (track != input->video_track);
|
| -
|
| - if (nestegg_packet_count(input->pkt, &input->chunks))
|
| - return 1;
|
| - input->chunk = 0;
|
| + if (new_buf) {
|
| + *buf = new_buf;
|
| + *buffer_size = 2 * bytes_to_read;
|
| + } else {
|
| + warn("Failed to allocate compressed data buffer\n");
|
| + bytes_to_read = 0;
|
| + }
|
| + }
|
| }
|
|
|
| - if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz))
|
| - return 1;
|
| - input->chunk++;
|
| -
|
| - return 0;
|
| - }
|
| - /* For both the raw and ivf formats, the frame size is the first 4 bytes
|
| - * of the frame header. We just need to special case on the header
|
| - * size.
|
| - */
|
| - else if (fread(raw_hdr, kind == IVF_FILE
|
| - ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) {
|
| - if (!feof(infile))
|
| - fprintf(stderr, "Failed to read frame size\n");
|
| -
|
| - new_buf_sz = 0;
|
| - } else {
|
| - new_buf_sz = mem_get_le32(raw_hdr);
|
| -
|
| - if (new_buf_sz > 256 * 1024 * 1024) {
|
| - fprintf(stderr, "Error: Read invalid frame size (%u)\n",
|
| - (unsigned int)new_buf_sz);
|
| - new_buf_sz = 0;
|
| - }
|
| -
|
| - if (kind == RAW_FILE && new_buf_sz > 256 * 1024)
|
| - fprintf(stderr, "Warning: Read invalid frame size (%u)"
|
| - " - not a raw file?\n", (unsigned int)new_buf_sz);
|
| -
|
| - if (new_buf_sz > *buf_alloc_sz) {
|
| - uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
|
| -
|
| - if (new_buf) {
|
| - *buf = new_buf;
|
| - *buf_alloc_sz = 2 * new_buf_sz;
|
| - } else {
|
| - fprintf(stderr, "Failed to allocate compressed data buffer\n");
|
| - new_buf_sz = 0;
|
| + if (!feof(infile)) {
|
| + if (fread(*buf, 1, bytes_to_read, infile) != bytes_to_read) {
|
| + warn("Failed to read full frame\n");
|
| + return 1;
|
| }
|
| + *bytes_in_buffer = bytes_to_read;
|
| }
|
| - }
|
|
|
| - *buf_sz = new_buf_sz;
|
| -
|
| - if (!feof(infile)) {
|
| - if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) {
|
| - fprintf(stderr, "Failed to read full frame\n");
|
| - return 1;
|
| - }
|
| -
|
| return 0;
|
| + } else if (kind == FILE_TYPE_IVF) {
|
| + return ivf_read_frame(input->vpx_input_ctx,
|
| + buf, bytes_in_buffer, buffer_size);
|
| }
|
|
|
| return 1;
|
| @@ -322,8 +246,7 @@
|
| : set_binary_mode(stdout);
|
|
|
| if (!outfile) {
|
| - fprintf(stderr, "Failed to output file");
|
| - exit(EXIT_FAILURE);
|
| + fatal("Failed to output file");
|
| }
|
| }
|
|
|
| @@ -359,254 +282,67 @@
|
| }
|
| }
|
|
|
| -unsigned int file_is_ivf(FILE *infile,
|
| - unsigned int *fourcc,
|
| - unsigned int *width,
|
| - unsigned int *height,
|
| - unsigned int *fps_den,
|
| - unsigned int *fps_num) {
|
| - char raw_hdr[32];
|
| - int is_ivf = 0;
|
| -
|
| - if (fread(raw_hdr, 1, 32, infile) == 32) {
|
| - if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
|
| - && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') {
|
| - is_ivf = 1;
|
| -
|
| - if (mem_get_le16(raw_hdr + 4) != 0)
|
| - fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
|
| - " decode properly.");
|
| -
|
| - *fourcc = mem_get_le32(raw_hdr + 8);
|
| - *width = mem_get_le16(raw_hdr + 12);
|
| - *height = mem_get_le16(raw_hdr + 14);
|
| - *fps_num = mem_get_le32(raw_hdr + 16);
|
| - *fps_den = mem_get_le32(raw_hdr + 20);
|
| -
|
| - /* Some versions of vpxenc used 1/(2*fps) for the timebase, so
|
| - * we can guess the framerate using only the timebase in this
|
| - * case. Other files would require reading ahead to guess the
|
| - * timebase, like we do for webm.
|
| - */
|
| - if (*fps_num < 1000) {
|
| - /* Correct for the factor of 2 applied to the timebase in the
|
| - * encoder.
|
| - */
|
| - if (*fps_num & 1)*fps_den <<= 1;
|
| - else *fps_num >>= 1;
|
| - } else {
|
| - /* Don't know FPS for sure, and don't have readahead code
|
| - * (yet?), so just default to 30fps.
|
| - */
|
| - *fps_num = 30;
|
| - *fps_den = 1;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (!is_ivf)
|
| - rewind(infile);
|
| -
|
| - return is_ivf;
|
| -}
|
| -
|
| -
|
| -unsigned int file_is_raw(FILE *infile,
|
| - unsigned int *fourcc,
|
| - unsigned int *width,
|
| - unsigned int *height,
|
| - unsigned int *fps_den,
|
| - unsigned int *fps_num) {
|
| - unsigned char buf[32];
|
| +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, infile) == 32) {
|
| + if (fread(buf, 1, 32, input->file) == 32) {
|
| int i;
|
|
|
| - if (mem_get_le32(buf) < 256 * 1024 * 1024)
|
| - for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
|
| + if (mem_get_le32(buf) < 256 * 1024 * 1024) {
|
| + for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) {
|
| if (!vpx_codec_peek_stream_info(ifaces[i].iface(),
|
| buf + 4, 32 - 4, &si)) {
|
| is_raw = 1;
|
| - *fourcc = ifaces[i].fourcc;
|
| - *width = si.w;
|
| - *height = si.h;
|
| - *fps_num = 30;
|
| - *fps_den = 1;
|
| + input->fourcc = ifaces[i].fourcc;
|
| + input->width = si.w;
|
| + input->height = si.h;
|
| + input->framerate.numerator = 30;
|
| + input->framerate.denominator = 1;
|
| break;
|
| }
|
| + }
|
| + }
|
| }
|
|
|
| - rewind(infile);
|
| + rewind(input->file);
|
| return is_raw;
|
| }
|
|
|
| -
|
| -static int
|
| -nestegg_read_cb(void *buffer, size_t length, void *userdata) {
|
| - FILE *f = userdata;
|
| -
|
| - if (fread(buffer, 1, length, f) < length) {
|
| - if (ferror(f))
|
| - return -1;
|
| - if (feof(f))
|
| - return 0;
|
| - }
|
| - return 1;
|
| +void show_progress(int frame_in, int frame_out, unsigned long dx_time) {
|
| + fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r",
|
| + frame_in, frame_out, dx_time,
|
| + (float)frame_out * 1000000.0 / (float)dx_time);
|
| }
|
|
|
| +// Called by libvpx if the frame buffer size needs to increase.
|
| +//
|
| +// Parameters:
|
| +// user_priv Data passed into libvpx.
|
| +// new_size Minimum size needed by libvpx to decompress the next frame.
|
| +// fb Pointer to the frame buffer to update.
|
| +//
|
| +// Returns 0 on success. Returns < 0 on failure.
|
| +int realloc_vp9_frame_buffer(void *user_priv, size_t new_size,
|
| + vpx_codec_frame_buffer_t *fb) {
|
| + (void)user_priv;
|
| + if (!fb)
|
| + return -1;
|
|
|
| -static int
|
| -nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
|
| - switch (whence) {
|
| - case NESTEGG_SEEK_SET:
|
| - whence = SEEK_SET;
|
| - break;
|
| - case NESTEGG_SEEK_CUR:
|
| - whence = SEEK_CUR;
|
| - break;
|
| - case NESTEGG_SEEK_END:
|
| - whence = SEEK_END;
|
| - break;
|
| - };
|
| - return fseek(userdata, (long)offset, whence) ? -1 : 0;
|
| -}
|
| -
|
| -
|
| -static int64_t
|
| -nestegg_tell_cb(void *userdata) {
|
| - return ftell(userdata);
|
| -}
|
| -
|
| -
|
| -static void
|
| -nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
|
| - ...) {
|
| - va_list ap;
|
| -
|
| - va_start(ap, format);
|
| - vfprintf(stderr, format, ap);
|
| - fprintf(stderr, "\n");
|
| - va_end(ap);
|
| -}
|
| -
|
| -
|
| -static int
|
| -webm_guess_framerate(struct input_ctx *input,
|
| - unsigned int *fps_den,
|
| - unsigned int *fps_num) {
|
| - unsigned int i;
|
| - uint64_t tstamp = 0;
|
| -
|
| - /* Check to see if we can seek before we parse any data. */
|
| - if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) {
|
| - fprintf(stderr,
|
| - "WARNING: Failed to guess framerate (no Cues), set to 30fps.\n");
|
| - *fps_num = 30;
|
| - *fps_den = 1;
|
| - return 0;
|
| + free(fb->data);
|
| + fb->data = (uint8_t*)malloc(new_size);
|
| + if (!fb->data) {
|
| + fb->size = 0;
|
| + return -1;
|
| }
|
|
|
| - /* Guess the framerate. Read up to 1 second, or 50 video packets,
|
| - * whichever comes first.
|
| - */
|
| - for (i = 0; tstamp < 1000000000 && i < 50;) {
|
| - nestegg_packet *pkt;
|
| - unsigned int track;
|
| -
|
| - if (nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0)
|
| - break;
|
| -
|
| - nestegg_packet_track(pkt, &track);
|
| - if (track == input->video_track) {
|
| - nestegg_packet_tstamp(pkt, &tstamp);
|
| - i++;
|
| - }
|
| -
|
| - nestegg_free_packet(pkt);
|
| - }
|
| -
|
| - if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0))
|
| - goto fail;
|
| -
|
| - *fps_num = (i - 1) * 1000000;
|
| - *fps_den = (unsigned int)(tstamp / 1000);
|
| + fb->size = new_size;
|
| return 0;
|
| -fail:
|
| - nestegg_destroy(input->nestegg_ctx);
|
| - input->nestegg_ctx = NULL;
|
| - rewind(input->infile);
|
| - return 1;
|
| }
|
|
|
| -
|
| -static int
|
| -file_is_webm(struct input_ctx *input,
|
| - unsigned int *fourcc,
|
| - unsigned int *width,
|
| - unsigned int *height,
|
| - unsigned int *fps_den,
|
| - unsigned int *fps_num) {
|
| - unsigned int i, n;
|
| - int track_type = -1;
|
| - int codec_id;
|
| -
|
| - nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
|
| - nestegg_video_params params;
|
| -
|
| - io.userdata = input->infile;
|
| - if (nestegg_init(&input->nestegg_ctx, io, NULL))
|
| - goto fail;
|
| -
|
| - if (nestegg_track_count(input->nestegg_ctx, &n))
|
| - goto fail;
|
| -
|
| - for (i = 0; i < n; i++) {
|
| - track_type = nestegg_track_type(input->nestegg_ctx, i);
|
| -
|
| - if (track_type == NESTEGG_TRACK_VIDEO)
|
| - break;
|
| - else if (track_type < 0)
|
| - goto fail;
|
| - }
|
| -
|
| - codec_id = nestegg_track_codec_id(input->nestegg_ctx, i);
|
| - if (codec_id == NESTEGG_CODEC_VP8) {
|
| - *fourcc = VP8_FOURCC;
|
| - } else if (codec_id == NESTEGG_CODEC_VP9) {
|
| - *fourcc = VP9_FOURCC;
|
| - } else {
|
| - fprintf(stderr, "Not VPx video, quitting.\n");
|
| - exit(1);
|
| - }
|
| -
|
| - input->video_track = i;
|
| -
|
| - if (nestegg_track_video_params(input->nestegg_ctx, i, ¶ms))
|
| - goto fail;
|
| -
|
| - *fps_den = 0;
|
| - *fps_num = 0;
|
| - *width = params.width;
|
| - *height = params.height;
|
| - return 1;
|
| -fail:
|
| - input->nestegg_ctx = NULL;
|
| - rewind(input->infile);
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -void show_progress(int frame_in, int frame_out, unsigned long dx_time) {
|
| - fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r",
|
| - frame_in, frame_out, dx_time,
|
| - (float)frame_out * 1000000.0 / (float)dx_time);
|
| -}
|
| -
|
| -
|
| void generate_filename(const char *pattern, char *out, size_t q_len,
|
| unsigned int d_w, unsigned int d_h,
|
| unsigned int frame_in) {
|
| @@ -688,18 +424,18 @@
|
|
|
|
|
| int main_loop(int argc, const char **argv_) {
|
| - vpx_codec_ctx_t decoder;
|
| + vpx_codec_ctx_t decoder;
|
| char *fn = NULL;
|
| int i;
|
| uint8_t *buf = NULL;
|
| - size_t buf_sz = 0, buf_alloc_sz = 0;
|
| + size_t bytes_in_buffer = 0, buffer_size = 0;
|
| FILE *infile;
|
| - int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
|
| + int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
|
| + int do_md5 = 0, progress = 0;
|
| int stop_after = 0, postproc = 0, summary = 0, quiet = 1;
|
| int arg_skip = 0;
|
| int ec_enabled = 0;
|
| vpx_codec_iface_t *iface = NULL;
|
| - unsigned int fourcc;
|
| unsigned long dx_time = 0;
|
| struct arg arg;
|
| char **argv, **argi, **argj;
|
| @@ -707,10 +443,6 @@
|
| char outfile[PATH_MAX];
|
| int single_file;
|
| int use_y4m = 1;
|
| - unsigned int width;
|
| - unsigned int height;
|
| - unsigned int fps_den;
|
| - unsigned int fps_num;
|
| void *out = NULL;
|
| vpx_codec_dec_cfg_t cfg = {0};
|
| #if CONFIG_VP8_DECODER
|
| @@ -720,14 +452,21 @@
|
| int vp8_dbg_color_b_modes = 0;
|
| int vp8_dbg_display_mv = 0;
|
| #endif
|
| - struct input_ctx input = {0};
|
| int frames_corrupted = 0;
|
| int dec_flags = 0;
|
| int do_scale = 0;
|
| - int stream_w = 0, stream_h = 0;
|
| vpx_image_t *scaled_img = NULL;
|
| int frame_avail, got_data;
|
| + int num_external_frame_buffers = 0;
|
| + int fb_lru_cache = 0;
|
| + vpx_codec_frame_buffer_t *frame_buffers = NULL;
|
|
|
| + struct VpxDecInputContext input = {0};
|
| + struct VpxInputContext vpx_input_ctx = {0};
|
| + struct WebmInputContext webm_ctx = {0};
|
| + input.vpx_input_ctx = &vpx_input_ctx;
|
| + input.webm_ctx = &webm_ctx;
|
| +
|
| /* Parse command line */
|
| exec_name = argv_[0];
|
| argv = argv_dup(argc - 1, argv_ + 1);
|
| @@ -780,6 +519,10 @@
|
| quiet = 0;
|
| else if (arg_match(&arg, &scalearg, argi))
|
| do_scale = 1;
|
| + else if (arg_match(&arg, &fb_arg, argi))
|
| + num_external_frame_buffers = arg_parse_uint(&arg);
|
| + else if (arg_match(&arg, &fb_lru_arg, argi))
|
| + fb_lru_cache = arg_parse_uint(&arg);
|
|
|
| #if CONFIG_VP8_DECODER
|
| else if (arg_match(&arg, &addnoise_level, argi)) {
|
| @@ -865,14 +608,13 @@
|
| return EXIT_FAILURE;
|
| }
|
| #endif
|
| - input.infile = infile;
|
| - if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den,
|
| - &fps_num))
|
| - input.kind = IVF_FILE;
|
| - else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num))
|
| - input.kind = WEBM_FILE;
|
| - else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num))
|
| - input.kind = RAW_FILE;
|
| + input.vpx_input_ctx->file = infile;
|
| + if (file_is_ivf(input.vpx_input_ctx))
|
| + input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
|
| + else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
|
| + input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
|
| + else if (file_is_raw(input.vpx_input_ctx))
|
| + input.vpx_input_ctx->file_type = FILE_TYPE_RAW;
|
| else {
|
| fprintf(stderr, "Unrecognized input file type.\n");
|
| return EXIT_FAILURE;
|
| @@ -899,7 +641,7 @@
|
|
|
| if (single_file && !noblit) {
|
| generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1,
|
| - width, height, 0);
|
| + vpx_input_ctx.width, vpx_input_ctx.height, 0);
|
| out = out_open(outfile, do_md5);
|
| }
|
|
|
| @@ -912,8 +654,8 @@
|
| return EXIT_FAILURE;
|
| }
|
|
|
| - if (input.kind == WEBM_FILE)
|
| - if (webm_guess_framerate(&input, &fps_den, &fps_num)) {
|
| + if (vpx_input_ctx.file_type == FILE_TYPE_WEBM)
|
| + if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) {
|
| fprintf(stderr, "Failed to guess framerate -- error parsing "
|
| "webm file?\n");
|
| return EXIT_FAILURE;
|
| @@ -924,21 +666,23 @@
|
| store one, and neither does VP8.
|
| That will have to wait until these tools support WebM natively.*/
|
| snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ",
|
| - width, height, fps_num, fps_den, 'p');
|
| + vpx_input_ctx.width, vpx_input_ctx.height,
|
| + vpx_input_ctx.framerate.numerator,
|
| + vpx_input_ctx.framerate.denominator,
|
| + 'p');
|
| out_put(out, (unsigned char *)buffer,
|
| (unsigned int)strlen(buffer), do_md5);
|
| }
|
|
|
| /* Try to determine the codec from the fourcc. */
|
| for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
|
| - if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) {
|
| - vpx_codec_iface_t *ivf_iface = ifaces[i].iface();
|
| + if ((vpx_input_ctx.fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) {
|
| + vpx_codec_iface_t *vpx_iface = ifaces[i].iface();
|
|
|
| - if (iface && iface != ivf_iface)
|
| - fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
|
| - ifaces[i].name);
|
| + if (iface && iface != vpx_iface)
|
| + warn("Header indicates codec: %s\n", ifaces[i].name);
|
| else
|
| - iface = ivf_iface;
|
| + iface = vpx_iface;
|
|
|
| break;
|
| }
|
| @@ -988,14 +732,38 @@
|
| #endif
|
|
|
|
|
| - if(arg_skip)
|
| - fprintf(stderr, "Skiping first %d frames.\n", arg_skip);
|
| + if (arg_skip)
|
| + fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
|
| while (arg_skip) {
|
| - if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz))
|
| + if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size))
|
| break;
|
| arg_skip--;
|
| }
|
|
|
| + if (num_external_frame_buffers > 0) {
|
| + // Allocate the frame buffer list, setting all of the values to 0.
|
| + // Including the size of frame buffers. Libvpx will request the
|
| + // application to realloc the frame buffer data if the size is too small.
|
| + frame_buffers = (vpx_codec_frame_buffer_t*)calloc(
|
| + num_external_frame_buffers, sizeof(*frame_buffers));
|
| + if (vpx_codec_set_frame_buffers(&decoder, frame_buffers,
|
| + num_external_frame_buffers,
|
| + realloc_vp9_frame_buffer,
|
| + NULL)) {
|
| + fprintf(stderr, "Failed to configure external frame buffers: %s\n",
|
| + vpx_codec_error(&decoder));
|
| + return EXIT_FAILURE;
|
| + }
|
| + }
|
| +
|
| + if (fb_lru_cache > 0 &&
|
| + vpx_codec_control(&decoder, VP9D_SET_FRAME_BUFFER_LRU_CACHE,
|
| + fb_lru_cache)) {
|
| + fprintf(stderr, "Failed to set frame buffer lru cache: %s\n",
|
| + vpx_codec_error(&decoder));
|
| + return EXIT_FAILURE;
|
| + }
|
| +
|
| frame_avail = 1;
|
| got_data = 0;
|
|
|
| @@ -1008,19 +776,19 @@
|
|
|
| frame_avail = 0;
|
| if (!stop_after || frame_in < stop_after) {
|
| - if(!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) {
|
| + if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
|
| frame_avail = 1;
|
| frame_in++;
|
|
|
| vpx_usec_timer_start(&timer);
|
|
|
| - if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) {
|
| + if (vpx_codec_decode(&decoder, buf, bytes_in_buffer, NULL, 0)) {
|
| const char *detail = vpx_codec_error_detail(&decoder);
|
| - fprintf(stderr, "Failed to decode frame: %s\n",
|
| - vpx_codec_error(&decoder));
|
| + warn("Failed to decode frame %d: %s",
|
| + frame_in, vpx_codec_error(&decoder));
|
|
|
| if (detail)
|
| - fprintf(stderr, " Additional information: %s\n", detail);
|
| + warn("Additional information: %s", detail);
|
| goto fail;
|
| }
|
|
|
| @@ -1041,8 +809,7 @@
|
| dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
|
|
|
| if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
|
| - fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n",
|
| - vpx_codec_error(&decoder));
|
| + warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
|
| goto fail;
|
| }
|
| frames_corrupted += corrupted;
|
| @@ -1063,9 +830,18 @@
|
| }
|
|
|
| if (do_scale) {
|
| + int stream_w = 0, stream_h = 0;
|
| if (img && frame_out == 1) {
|
| - stream_w = img->d_w;
|
| - stream_h = img->d_h;
|
| + int display_size[2];
|
| + if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE,
|
| + display_size)) {
|
| + // Fallback to use raw image size if display size not available.
|
| + stream_w = img->d_w;
|
| + stream_h = img->d_h;
|
| + } else {
|
| + stream_w = display_size[0];
|
| + stream_h = display_size[1];
|
| + }
|
| scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420,
|
| stream_w, stream_h, 16);
|
| }
|
| @@ -1086,7 +862,6 @@
|
| img = scaled_img;
|
| }
|
| }
|
| -
|
| if (img) {
|
| unsigned int y;
|
| char out_fn[PATH_MAX];
|
| @@ -1149,17 +924,25 @@
|
| fail:
|
|
|
| if (vpx_codec_destroy(&decoder)) {
|
| - fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
|
| + fprintf(stderr, "Failed to destroy decoder: %s\n",
|
| + vpx_codec_error(&decoder));
|
| return EXIT_FAILURE;
|
| }
|
|
|
| if (single_file && !noblit)
|
| out_close(out, outfile, do_md5);
|
|
|
| - if (input.nestegg_ctx)
|
| - nestegg_destroy(input.nestegg_ctx);
|
| - if (input.kind != WEBM_FILE)
|
| + if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
|
| + webm_free(input.webm_ctx);
|
| + else
|
| free(buf);
|
| +
|
| + if (scaled_img) vpx_img_free(scaled_img);
|
| + for (i = 0; i < num_external_frame_buffers; ++i) {
|
| + free(frame_buffers[i].data);
|
| + }
|
| + free(frame_buffers);
|
| +
|
| fclose(infile);
|
| free(argv);
|
|
|
|
|