Index: source/libvpx/vpxdec.c |
=================================================================== |
--- source/libvpx/vpxdec.c (revision 251189) |
+++ source/libvpx/vpxdec.c (working copy) |
@@ -37,19 +37,6 @@ |
static const char *exec_name; |
-static const struct { |
- char const *name; |
- const vpx_codec_iface_t *(*iface)(void); |
- uint32_t fourcc; |
-} ifaces[] = { |
-#if CONFIG_VP8_DECODER |
- {"vp8", vpx_codec_vp8_dx, VP8_FOURCC}, |
-#endif |
-#if CONFIG_VP9_DECODER |
- {"vp9", vpx_codec_vp9_dx, VP9_FOURCC}, |
-#endif |
-}; |
- |
struct VpxDecInputContext { |
struct VpxInputContext *vpx_input_ctx; |
struct WebmInputContext *webm_ctx; |
@@ -88,6 +75,8 @@ |
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"); |
@@ -95,7 +84,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, |
&md5arg, |
&error_concealment, |
NULL |
@@ -170,10 +159,11 @@ |
); |
fprintf(stderr, "\nIncluded decoders:\n\n"); |
- for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
+ for (i = 0; i < get_vpx_decoder_count(); ++i) { |
+ const VpxInterface *const decoder = get_vpx_decoder_by_index(i); |
fprintf(stderr, " %-6s - %s\n", |
- ifaces[i].name, |
- vpx_codec_iface_name(ifaces[i].iface())); |
+ decoder->name, vpx_codec_iface_name(decoder->interface())); |
+ } |
exit(EXIT_FAILURE); |
} |
@@ -187,8 +177,8 @@ |
if (!feof(infile)) |
warn("Failed to read RAW frame size\n"); |
} else { |
- const int kCorruptFrameThreshold = 256 * 1024 * 1024; |
- const int kFrameTooSmallThreshold = 256 * 1024; |
+ const size_t kCorruptFrameThreshold = 256 * 1024 * 1024; |
+ const size_t kFrameTooSmallThreshold = 256 * 1024; |
frame_size = mem_get_le32(raw_hdr); |
if (frame_size > kCorruptFrameThreshold) { |
@@ -241,18 +231,6 @@ |
} |
} |
-static int get_image_plane_width(int plane, const vpx_image_t *img) { |
- return (plane > 0 && img->x_chroma_shift > 0) ? |
- (img->d_w + 1) >> img->x_chroma_shift : |
- img->d_w; |
-} |
- |
-static int get_image_plane_height(int plane, const vpx_image_t *img) { |
- return (plane > 0 && img->y_chroma_shift > 0) ? |
- (img->d_h + 1) >> img->y_chroma_shift : |
- img->d_h; |
-} |
- |
static void update_image_md5(const vpx_image_t *img, const int planes[3], |
MD5Context *md5) { |
int i, y; |
@@ -261,8 +239,8 @@ |
const int plane = planes[i]; |
const unsigned char *buf = img->planes[plane]; |
const int stride = img->stride[plane]; |
- const int w = get_image_plane_width(plane, img); |
- const int h = get_image_plane_height(plane, img); |
+ const int w = vpx_img_plane_width(img, plane); |
+ const int h = vpx_img_plane_height(img, plane); |
for (y = 0; y < h; ++y) { |
MD5Update(md5, buf, w); |
@@ -279,8 +257,8 @@ |
const int plane = planes[i]; |
const unsigned char *buf = img->planes[plane]; |
const int stride = img->stride[plane]; |
- const int w = get_image_plane_width(plane, img); |
- const int h = get_image_plane_height(plane, img); |
+ 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, 1, w, file); |
@@ -300,11 +278,12 @@ |
int 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(), |
+ 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->interface(), |
buf + 4, 32 - 4, &si)) { |
is_raw = 1; |
- input->fourcc = ifaces[i].fourcc; |
+ input->fourcc = decoder->fourcc; |
input->width = si.w; |
input->height = si.h; |
input->framerate.numerator = 30; |
@@ -325,6 +304,68 @@ |
(float)frame_out * 1000000.0 / (float)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, |
unsigned int d_w, unsigned int d_h, |
unsigned int frame_in) { |
@@ -441,7 +482,6 @@ |
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; |
@@ -450,7 +490,8 @@ |
int stop_after = 0, postproc = 0, summary = 0, quiet = 1; |
int arg_skip = 0; |
int ec_enabled = 0; |
- vpx_codec_iface_t *iface = NULL; |
+ const VpxInterface *interface = NULL; |
+ const VpxInterface *fourcc_interface = NULL; |
unsigned long dx_time = 0; |
struct arg arg; |
char **argv, **argi, **argj; |
@@ -470,6 +511,8 @@ |
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}; |
@@ -493,17 +536,9 @@ |
arg.argv_step = 1; |
if (arg_match(&arg, &codecarg, argi)) { |
- int j, k = -1; |
- |
- for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) |
- if (!strcmp(ifaces[j].name, arg.val)) |
- k = j; |
- |
- if (k >= 0) |
- iface = ifaces[k].iface(); |
- else |
- die("Error: Unrecognized argument (%s) to --codec\n", |
- arg.val); |
+ interface = get_vpx_decoder_by_name(arg.val); |
+ if (!interface) |
+ die("Error: Unrecognized argument (%s) to --codec\n", arg.val); |
} else if (arg_match(&arg, &looparg, argi)) { |
// no-op |
} else if (arg_match(&arg, &outputfile, argi)) |
@@ -536,6 +571,8 @@ |
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)) { |
@@ -660,24 +697,20 @@ |
} |
} |
- /* Try to determine the codec from the fourcc. */ |
- for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
- if (vpx_input_ctx.fourcc == ifaces[i].fourcc) { |
- vpx_codec_iface_t *vpx_iface = ifaces[i].iface(); |
+ fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc); |
+ if (interface && fourcc_interface && interface != fourcc_interface) |
+ warn("Header indicates codec: %s\n", fourcc_interface->name); |
+ else |
+ interface = fourcc_interface; |
- if (iface && iface != vpx_iface) |
- warn("Header indicates codec: %s\n", ifaces[i].name); |
- else |
- iface = vpx_iface; |
+ if (!interface) |
+ interface = get_vpx_decoder_by_index(0); |
- break; |
- } |
- |
dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | |
(ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); |
- if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface(), &cfg, |
- dec_flags)) { |
- fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder)); |
+ if (vpx_codec_dec_init(&decoder, interface->interface(), &cfg, dec_flags)) { |
+ fprintf(stderr, "Failed to initialize decoder: %s\n", |
+ vpx_codec_error(&decoder)); |
return EXIT_FAILURE; |
} |
@@ -726,6 +759,19 @@ |
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; |
@@ -898,6 +944,11 @@ |
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); |