#define VPX_CODEC_DISABLE_COMPAT 1
#include "./vpx_config.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
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 md5arg = ARG_DEF(NULL, "md5", 0,
"Compute the MD5 sum of the decoded frame");
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,
&md5arg,
&error_concealment,
NULL
#endif
static int vpx_image_scale(vpx_image_t *src, vpx_image_t *dst,
- FilterMode mode) {
+ FilterModeEnum mode) {
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],
static int 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, buffer_size);
+#endif
case FILE_TYPE_RAW:
return raw_read_frame(input->vpx_input_ctx->file,
buf, bytes_in_buffer, buffer_size);
return is_raw;
}
-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",
+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,
- (float)frame_out * 1000000.0 / (float)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.
+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 *)malloc(min_size);
+ 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.
+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;
}
void generate_filename(const char *pattern, char *out, size_t q_len,
int main_loop(int argc, const char **argv_) {
vpx_codec_ctx_t decoder;
char *fn = NULL;
+ int i;
uint8_t *buf = NULL;
size_t bytes_in_buffer = 0, buffer_size = 0;
FILE *infile;
int ec_enabled = 0;
const VpxInterface *interface = NULL;
const VpxInterface *fourcc_interface = NULL;
- unsigned long dx_time = 0;
+ uint64_t dx_time = 0;
struct arg arg;
char **argv, **argi, **argj;
int do_scale = 0;
vpx_image_t *scaled_img = NULL;
int frame_avail, got_data;
+ int num_external_frame_buffers = 0;
+ struct ExternalFrameBufferList ext_fb_list = {0};
const char *outfile_pattern = NULL;
char outfile_name[PATH_MAX] = {0};
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);
#if CONFIG_VP8_DECODER
else if (arg_match(&arg, &addnoise_level, argi)) {
input.vpx_input_ctx->file = infile;
if (file_is_ivf(input.vpx_input_ctx))
input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
+#if CONFIG_WEBM_IO
else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
+#endif
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");
+#if !CONFIG_WEBM_IO
+ fprintf(stderr, "vpxdec was built without WebM container support.\n");
+#endif
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
+#if CONFIG_WEBM_IO
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 "
return EXIT_FAILURE;
}
}
+#endif
}
fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc);
arg_skip--;
}
+ if (num_external_frame_buffers > 0) {
+ ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
+ ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
+ num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
+ if (vpx_codec_set_frame_buffer_functions(
+ &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer,
+ &ext_fb_list)) {
+ fprintf(stderr, "Failed to configure external frame buffers: %s\n",
+ vpx_codec_error(&decoder));
+ return EXIT_FAILURE;
+ }
+ }
+
frame_avail = 1;
got_data = 0;
vpx_usec_timer_start(&timer);
- if (vpx_codec_decode(&decoder, buf, bytes_in_buffer, NULL, 0)) {
+ if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer,
+ NULL, 0)) {
const char *detail = vpx_codec_error_detail(&decoder);
warn("Failed to decode frame %d: %s",
frame_in, vpx_codec_error(&decoder));
}
vpx_usec_timer_mark(&timer);
- dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
+ dx_time += vpx_usec_timer_elapsed(&timer);
}
}
vpx_input_ctx.height,
&vpx_input_ctx.framerate, img->fmt);
if (do_md5) {
- MD5Update(&md5_ctx, (md5byte *)buf, len);
+ MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
} else {
fputs(buf, outfile);
}
// Y4M frame header
len = y4m_write_frame_header(buf, sizeof(buf));
if (do_md5) {
- MD5Update(&md5_ctx, (md5byte *)buf, len);
+ MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
} else {
fputs(buf, outfile);
}
}
}
+#if CONFIG_WEBM_IO
if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
webm_free(input.webm_ctx);
- else
+#endif
+
+ if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM)
free(buf);
if (scaled_img) vpx_img_free(scaled_img);
+ for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
+ free(ext_fb_list.ext_fb[i].data);
+ }
+ free(ext_fb_list.ext_fb);
+
fclose(infile);
free(argv);