X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fthird_party%2Flibvpx%2Fsource%2Flibvpx%2Fvpxdec.c;h=6c1ce11dcd7319c89d5dcf2551f7fb60092960cb;hb=ff3e2503a20db9193d323c1d19c38c68004dec4a;hp=91d8faf01207f6c04c1d747d9d334651d66d74cf;hpb=7338fba38ba696536d1cc9d389afd716a6ab2fe6;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/third_party/libvpx/source/libvpx/vpxdec.c b/src/third_party/libvpx/source/libvpx/vpxdec.c index 91d8faf..6c1ce11 100644 --- a/src/third_party/libvpx/source/libvpx/vpxdec.c +++ b/src/third_party/libvpx/source/libvpx/vpxdec.c @@ -29,29 +29,14 @@ #include "vpx/vp8dx.h" #endif -#if CONFIG_MD5 #include "./md5_utils.h" -#endif #include "./tools_common.h" #include "./webmdec.h" +#include "./y4menc.h" static const char *exec_name; -static const struct { - char const *name; - const vpx_codec_iface_t *(*iface)(void); - uint32_t fourcc; - uint32_t fourcc_mask; -} ifaces[] = { -#if CONFIG_VP8_DECODER - {"vp8", vpx_codec_vp8_dx, VP8_FOURCC_MASK, 0x00FFFFFF}, -#endif -#if CONFIG_VP9_DECODER - {"vp9", vpx_codec_vp9_dx, VP9_FOURCC_MASK, 0x00FFFFFF}, -#endif -}; - struct VpxDecInputContext { struct VpxInputContext *vpx_input_ctx; struct WebmInputContext *webm_ctx; @@ -89,23 +74,18 @@ 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 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 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, "Compute the MD5 sum of the decoded frame"); -#endif + static const arg_def_t *all_args[] = { &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile, - &threadsarg, &verbosearg, &scalearg, &fb_arg, &fb_lru_arg, -#if CONFIG_MD5 + &threadsarg, &verbosearg, &scalearg, &fb_arg, &md5arg, -#endif &error_concealment, NULL }; @@ -137,6 +117,21 @@ static const arg_def_t *vp8_pp_args[] = { }; #endif +static int vpx_image_scale(vpx_image_t *src, vpx_image_t *dst, + FilterMode 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], + 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); +} + void usage_exit() { int i; @@ -164,121 +159,111 @@ void usage_exit() { ); 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); } -static int read_frame(struct VpxDecInputContext *input, - uint8_t **buf, - size_t *bytes_in_buffer, - size_t *buffer_size) { +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 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); - - if (bytes_to_read > kCorruptFrameThreshold) { - warn("Read invalid frame size (%u)\n", (unsigned int)bytes_to_read); - bytes_to_read = 0; - } + size_t frame_size = 0; - 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); - } + 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 (bytes_to_read > *buffer_size) { - uint8_t *new_buf = realloc(*buf, 2 * bytes_to_read); + if (frame_size > kCorruptFrameThreshold) { + warn("Read invalid frame size (%u)\n", (unsigned int)frame_size); + frame_size = 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 (frame_size < kFrameTooSmallThreshold) { + warn("Warning: Read invalid frame size (%u) - not a raw file?\n", + (unsigned int)frame_size); } - if (!feof(infile)) { - if (fread(*buf, 1, bytes_to_read, infile) != bytes_to_read) { - warn("Failed to read full frame\n"); - return 1; + 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; } - *bytes_in_buffer = bytes_to_read; } - - return 0; - } else if (kind == FILE_TYPE_IVF) { - return ivf_read_frame(input->vpx_input_ctx, - buf, bytes_in_buffer, buffer_size); } - return 1; -} - -void *out_open(const char *out_fn, int do_md5) { - void *out = NULL; - - if (do_md5) { -#if CONFIG_MD5 - MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); - (void)out_fn; - MD5Init(md5_ctx); -#endif - } else { - FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") - : set_binary_mode(stdout); - - if (!outfile) { - fatal("Failed to output file"); + 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 out; + return 0; } -void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) { - if (do_md5) { -#if CONFIG_MD5 - MD5Update(out, buf, len); -#endif - } else { - (void) fwrite(buf, 1, len, out); +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) { + case FILE_TYPE_WEBM: + return webm_read_frame(input->webm_ctx, + buf, bytes_in_buffer, buffer_size); + 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; } } -void out_close(void *out, const char *out_fn, int do_md5) { - if (do_md5) { -#if CONFIG_MD5 - uint8_t md5[16]; - int i; +static void update_image_md5(const vpx_image_t *img, const int planes[3], + MD5Context *md5) { + int i, y; - MD5Final(md5, out); - free(out); + 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 (i = 0; i < 16; i++) - printf("%02x", md5[i]); + for (y = 0; y < h; ++y) { + MD5Update(md5, buf, w); + buf += stride; + } + } +} - printf(" %s\n", out_fn); -#endif - } else { - fclose(out); +static void write_image_file(const vpx_image_t *img, const int planes[3], + FILE *file) { + 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); + const int h = vpx_img_plane_height(img, plane); + + for (y = 0; y < h; ++y) { + fwrite(buf, 1, w, file); + buf += stride; + } } } @@ -293,11 +278,12 @@ int file_is_raw(struct VpxInputContext *input) { 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; @@ -318,28 +304,65 @@ void show_progress(int frame_in, int frame_out, unsigned long 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) +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; - free(fb->data); - fb->data = (uint8_t*)malloc(new_size); - if (!fb->data) { - fb->size = 0; + // 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->size = new_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; } @@ -422,11 +445,43 @@ void generate_filename(const char *pattern, char *out, size_t q_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; + } else { + FILE *file = fopen(name, "wb"); + if (!file) + fatal("Failed to output file %s", name); + return file; + } +} 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; @@ -435,15 +490,14 @@ int main_loop(int argc, const char **argv_) { 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; - const char *outfile_pattern = 0; - char outfile[PATH_MAX]; + int single_file; int use_y4m = 1; - void *out = NULL; vpx_codec_dec_cfg_t cfg = {0}; #if CONFIG_VP8_DECODER vp8_postproc_cfg_t vp8_pp_cfg = {0}; @@ -458,8 +512,14 @@ int main_loop(int argc, const char **argv_) { 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 ExternalFrameBufferList ext_fb_list = {0}; + + const char *outfile_pattern = NULL; + char outfile_name[PATH_MAX] = {0}; + FILE *outfile = NULL; + + MD5Context md5_ctx; + unsigned char md5_digest[16]; struct VpxDecInputContext input = {0}; struct VpxInputContext vpx_input_ctx = {0}; @@ -476,17 +536,9 @@ int main_loop(int argc, const char **argv_) { 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)) @@ -521,8 +573,6 @@ int main_loop(int argc, const char **argv_) { 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)) { @@ -595,8 +645,7 @@ int main_loop(int argc, const char **argv_) { infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); if (!infile) { - fprintf(stderr, "Failed to open file '%s'", - strcmp(fn, "-") ? fn : "stdin"); + fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin"); return EXIT_FAILURE; } #if CONFIG_OS_SUPPORT @@ -620,78 +669,48 @@ int main_loop(int argc, const char **argv_) { return EXIT_FAILURE; } - /* If the output file is not set or doesn't have a sequence number in - * it, then we only open it once. - */ outfile_pattern = outfile_pattern ? outfile_pattern : "-"; - single_file = 1; - { - const char *p = outfile_pattern; - do { - p = strchr(p, '%'); - if (p && p[1] >= '1' && p[1] <= '9') { - /* pattern contains sequence number, so it's not unique. */ - single_file = 0; - break; - } - if (p) - p++; - } while (p); - } + single_file = is_single_file(outfile_pattern); - if (single_file && !noblit) { - generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1, + if (!noblit && single_file) { + generate_filename(outfile_pattern, outfile_name, PATH_MAX, vpx_input_ctx.width, vpx_input_ctx.height, 0); - out = out_open(outfile, do_md5); + if (do_md5) + MD5Init(&md5_ctx); + else + outfile = open_outfile(outfile_name); } if (use_y4m && !noblit) { - char buffer[128]; - if (!single_file) { fprintf(stderr, "YUV4MPEG2 not supported with output patterns," " try --i420 or --yv12.\n"); return EXIT_FAILURE; } - if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) + 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; } - - - /*Note: We can't output an aspect ratio here because IVF doesn't - 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 ", - 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 ((vpx_input_ctx.fourcc & ifaces[i].fourcc_mask) == 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; - - break; - } + if (!interface) + interface = get_vpx_decoder_by_index(0); 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; } @@ -741,29 +760,18 @@ int main_loop(int argc, const char **argv_) { } 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)) { + 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; } } - 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; @@ -817,95 +825,86 @@ int main_loop(int argc, const char **argv_) { if (progress) show_progress(frame_in, frame_out, dx_time); - if (!noblit) { - if (frame_out == 1 && img && use_y4m) { - /* Write out the color format to terminate the header line */ - const char *color = - img->fmt == VPX_IMG_FMT_444A ? "C444alpha\n" : - img->fmt == VPX_IMG_FMT_I444 ? "C444\n" : - img->fmt == VPX_IMG_FMT_I422 ? "C422\n" : - "C420jpeg\n"; - - out_put(out, (const unsigned char*)color, strlen(color), do_md5); - } + if (!noblit && img) { + const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V}; + const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U}; + const int *planes = flipuv ? PLANES_YVU : PLANES_YUV; if (do_scale) { - int stream_w = 0, stream_h = 0; - if (img && frame_out == 1) { - 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]; + if (frame_out == 1) { + // If the output frames are to be scaled to a fixed display size then + // use the width and height specified in the container. If either of + // these is set to 0, use the display size set in the first frame + // header. If that is unavailable, use the raw decoded size of the + // first decoded frame. + int display_width = vpx_input_ctx.width; + int display_height = vpx_input_ctx.height; + if (!display_width || !display_height) { + int display_size[2]; + if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE, + display_size)) { + // As last resort use size of first frame as display size. + display_width = img->d_w; + display_height = img->d_h; + } else { + display_width = display_size[0]; + display_height = display_size[1]; + } } - scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, - stream_w, stream_h, 16); + scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width, + display_height, 16); } - if (img && (img->d_w != stream_w || img->d_h != stream_h)) { - assert(img->fmt == VPX_IMG_FMT_I420); - I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], - img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], - img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], - img->d_w, img->d_h, - scaled_img->planes[VPX_PLANE_Y], - scaled_img->stride[VPX_PLANE_Y], - scaled_img->planes[VPX_PLANE_U], - scaled_img->stride[VPX_PLANE_U], - scaled_img->planes[VPX_PLANE_V], - scaled_img->stride[VPX_PLANE_V], - stream_w, stream_h, - kFilterBox); + + if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) { + vpx_image_scale(img, scaled_img, kFilterBox); img = scaled_img; } } - if (img) { - unsigned int y; - char out_fn[PATH_MAX]; - uint8_t *buf; - unsigned int c_w = - img->x_chroma_shift ? (1 + img->d_w) >> img->x_chroma_shift - : img->d_w; - unsigned int c_h = - img->y_chroma_shift ? (1 + img->d_h) >> img->y_chroma_shift - : img->d_h; - - if (!single_file) { - size_t len = sizeof(out_fn) - 1; - - out_fn[len] = '\0'; - generate_filename(outfile_pattern, out_fn, len - 1, - img->d_w, img->d_h, frame_in); - out = out_open(out_fn, do_md5); - } else if (use_y4m) - out_put(out, (unsigned char *)"FRAME\n", 6, do_md5); - - buf = img->planes[VPX_PLANE_Y]; - - for (y = 0; y < img->d_h; y++) { - out_put(out, buf, img->d_w, do_md5); - buf += img->stride[VPX_PLANE_Y]; - } - buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U]; + if (single_file) { + if (use_y4m) { + char buf[Y4M_BUFFER_SIZE] = {0}; + size_t len = 0; + if (frame_out == 1) { + // Y4M file header + len = y4m_write_file_header(buf, sizeof(buf), + vpx_input_ctx.width, + vpx_input_ctx.height, + &vpx_input_ctx.framerate, img->fmt); + if (do_md5) { + MD5Update(&md5_ctx, (md5byte *)buf, len); + } else { + fputs(buf, outfile); + } + } - for (y = 0; y < c_h; y++) { - out_put(out, buf, c_w, do_md5); - buf += img->stride[VPX_PLANE_U]; + // Y4M frame header + len = y4m_write_frame_header(buf, sizeof(buf)); + if (do_md5) { + MD5Update(&md5_ctx, (md5byte *)buf, len); + } else { + fputs(buf, outfile); + } } - buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V]; - - for (y = 0; y < c_h; y++) { - out_put(out, buf, c_w, do_md5); - buf += img->stride[VPX_PLANE_V]; + if (do_md5) { + update_image_md5(img, planes, &md5_ctx); + } else { + write_image_file(img, planes, outfile); + } + } else { + generate_filename(outfile_pattern, outfile_name, PATH_MAX, + img->d_w, img->d_h, frame_in); + if (do_md5) { + MD5Init(&md5_ctx); + update_image_md5(img, planes, &md5_ctx); + MD5Final(md5_digest, &md5_ctx); + print_md5(md5_digest, outfile_name); + } else { + outfile = open_outfile(outfile_name); + write_image_file(img, planes, outfile); + fclose(outfile); } - - if (!single_file) - out_close(out, out_fn, do_md5); } } @@ -929,8 +928,14 @@ fail: return EXIT_FAILURE; } - if (single_file && !noblit) - out_close(out, outfile, do_md5); + if (!noblit && single_file) { + if (do_md5) { + MD5Final(md5_digest, &md5_ctx); + print_md5(md5_digest, outfile_name); + } else { + fclose(outfile); + } + } if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM) webm_free(input.webm_ctx); @@ -938,10 +943,11 @@ fail: free(buf); if (scaled_img) vpx_img_free(scaled_img); - for (i = 0; i < num_external_frame_buffers; ++i) { - free(frame_buffers[i].data); + + for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) { + free(ext_fb_list.ext_fb[i].data); } - free(frame_buffers); + free(ext_fb_list.ext_fb); fclose(infile); free(argv);