From da58436f43095743d77f7ee84500fd22851317d8 Mon Sep 17 00:00:00 2001 From: John Koleszar Date: Mon, 6 May 2013 15:52:06 -0700 Subject: [PATCH] Subsampling aware allocs and bitstream Make framebuffer allocations according to the chroma subsamping factors in use. A bit is placed in the raw part of the frame header for each of the two subsampling factors. This will be moved in a future commit to make them part of the TBD feature set bits, probably only set on keyframes, etc. Change-Id: I59ed38d3a3c0d4af3c7c277617de28d04a001853 --- vp9/common/vp9_alloccommon.c | 21 +++++----- vp9/common/vp9_blockd.h | 3 +- vp9/common/vp9_mbpitch.c | 7 ++-- vp9/common/vp9_onyxc_int.h | 6 +++ vp9/common/vp9_postproc.c | 6 --- vp9/decoder/vp9_decodframe.c | 9 +++-- vp9/encoder/vp9_bitstream.c | 2 + vp9/encoder/vp9_encodeframe.c | 2 +- vp9/encoder/vp9_firstpass.c | 2 +- vp9/encoder/vp9_lookahead.c | 9 +++-- vp9/encoder/vp9_lookahead.h | 2 + vp9/encoder/vp9_onyx_if.c | 82 +++++++++++++++++++++++++-------------- vp9/vp9_cx_iface.c | 50 ++++++------------------ vp9/vp9_iface_common.h | 23 ++++++++--- vpx_scale/generic/yv12config.c | 88 +++++++++++++++++++++++++++++++++++++++++- vpx_scale/yv12config.h | 8 ++++ vpxdec.c | 32 ++++++++++++--- 17 files changed, 243 insertions(+), 109 deletions(-) diff --git a/vp9/common/vp9_alloccommon.c b/vp9/common/vp9_alloccommon.c index a4120c2..ec81fbd 100644 --- a/vp9/common/vp9_alloccommon.c +++ b/vp9/common/vp9_alloccommon.c @@ -52,10 +52,10 @@ void vp9_free_frame_buffers(VP9_COMMON *oci) { int i; for (i = 0; i < NUM_YV12_BUFFERS; i++) - vp8_yv12_de_alloc_frame_buffer(&oci->yv12_fb[i]); + vp9_free_frame_buffer(&oci->yv12_fb[i]); - vp8_yv12_de_alloc_frame_buffer(&oci->temp_scale_frame); - vp8_yv12_de_alloc_frame_buffer(&oci->post_proc_buffer); + vp9_free_frame_buffer(&oci->temp_scale_frame); + vp9_free_frame_buffer(&oci->post_proc_buffer); vpx_free(oci->mip); vpx_free(oci->prev_mip); @@ -80,8 +80,9 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) { for (i = 0; i < NUM_YV12_BUFFERS; i++) { oci->fb_idx_ref_cnt[i] = 0; - if (vp8_yv12_alloc_frame_buffer(&oci->yv12_fb[i], width, height, - VP9BORDERINPIXELS) < 0) { + if (vp9_alloc_frame_buffer(&oci->yv12_fb[i], width, height, + oci->subsampling_x, oci->subsampling_y, + VP9BORDERINPIXELS) < 0) { vp9_free_frame_buffers(oci); return 1; } @@ -98,14 +99,16 @@ int vp9_alloc_frame_buffers(VP9_COMMON *oci, int width, int height) { oci->fb_idx_ref_cnt[i] = 1; } - if (vp8_yv12_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, - VP9BORDERINPIXELS) < 0) { + if (vp9_alloc_frame_buffer(&oci->temp_scale_frame, width, 16, + oci->subsampling_x, oci->subsampling_y, + VP9BORDERINPIXELS) < 0) { vp9_free_frame_buffers(oci); return 1; } - if (vp8_yv12_alloc_frame_buffer(&oci->post_proc_buffer, width, height, - VP9BORDERINPIXELS) < 0) { + if (vp9_alloc_frame_buffer(&oci->post_proc_buffer, width, height, + oci->subsampling_x, oci->subsampling_y, + VP9BORDERINPIXELS) < 0) { vp9_free_frame_buffers(oci); return 1; } diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index b621b0f..ab9e28d 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -692,7 +692,8 @@ static TX_TYPE get_tx_type_16x16(const MACROBLOCKD *xd, int ib) { return tx_type; } -void vp9_setup_block_dptrs(MACROBLOCKD *xd); +void vp9_setup_block_dptrs(MACROBLOCKD *xd, + int subsampling_x, int subsampling_y); static TX_SIZE get_uv_tx_size(const MACROBLOCKD *xd) { MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi; diff --git a/vp9/common/vp9_mbpitch.c b/vp9/common/vp9_mbpitch.c index 8c05a34..d9f892b 100644 --- a/vp9/common/vp9_mbpitch.c +++ b/vp9/common/vp9_mbpitch.c @@ -11,12 +11,13 @@ #include "vp9/common/vp9_blockd.h" -void vp9_setup_block_dptrs(MACROBLOCKD *mb) { +void vp9_setup_block_dptrs(MACROBLOCKD *mb, + int subsampling_x, int subsampling_y) { int i; for (i = 0; i < MAX_MB_PLANE; i++) { mb->plane[i].plane_type = i ? PLANE_TYPE_UV : PLANE_TYPE_Y_WITH_DC; - mb->plane[i].subsampling_x = !!i; - mb->plane[i].subsampling_y = !!i; + mb->plane[i].subsampling_x = i ? subsampling_x : 0; + mb->plane[i].subsampling_y = i ? subsampling_y : 0; } } diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 9f0c712..3e8bb15 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -132,6 +132,12 @@ typedef struct VP9Common { int last_width; int last_height; + // TODO(jkoleszar): this implies chroma ss right now, but could vary per + // plane. Revisit as part of the future change to YV12_BUFFER_CONFIG to + // support additional planes. + int subsampling_x; + int subsampling_y; + YUV_TYPE clr_type; CLAMP_TYPE clamp_type; diff --git a/vp9/common/vp9_postproc.c b/vp9/common/vp9_postproc.c index f93b74c..f81690a 100644 --- a/vp9/common/vp9_postproc.c +++ b/vp9/common/vp9_postproc.c @@ -631,13 +631,7 @@ int vp9_post_proc_frame(VP9_COMMON *oci, YV12_BUFFER_CONFIG *dest, if (!flags) { *dest = *oci->frame_to_show; - - /* handle problem with extending borders */ - dest->y_width = oci->width; - dest->y_height = oci->height; - dest->uv_height = dest->y_height / 2; return 0; - } #if ARCH_X86||ARCH_X86_64 diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c index 54e06f5..4be3677 100644 --- a/vp9/decoder/vp9_decodframe.c +++ b/vp9/decoder/vp9_decodframe.c @@ -929,6 +929,8 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) { pc->version = (data[0] >> 1) & 7; pc->show_frame = (data[0] >> 4) & 1; scaling_active = (data[0] >> 5) & 1; + pc->subsampling_x = (data[0] >> 6) & 1; + pc->subsampling_y = (data[0] >> 7) & 1; first_partition_size = read_le16(data + 1); if (!read_is_valid(data, first_partition_size, data_end)) @@ -961,8 +963,9 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) { init_frame(pbi); // Reset the frame pointers to the current frame size - vp8_yv12_realloc_frame_buffer(new_fb, pc->width, pc->height, - VP9BORDERINPIXELS); + vp9_realloc_frame_buffer(new_fb, pc->width, pc->height, + pc->subsampling_x, pc->subsampling_y, + VP9BORDERINPIXELS); if (vp9_reader_init(&header_bc, data, first_partition_size)) vpx_internal_error(&pc->error, VPX_CODEC_MEM_ERROR, @@ -1073,7 +1076,7 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) { CHECK_MEM_ERROR(pc->last_frame_seg_map, vpx_calloc((pc->mi_rows * pc->mi_cols), 1)); - vp9_setup_block_dptrs(xd); + vp9_setup_block_dptrs(xd, pc->subsampling_x, pc->subsampling_y); // clear out the coeff buffer for (i = 0; i < MAX_MB_PLANE; ++i) diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 20154d8..da0bb21 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -1805,6 +1805,8 @@ void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, unsigned long *size) { int scaling = (pc->width != pc->display_width || pc->height != pc->display_height); int v = (oh.first_partition_length_in_bytes << 8) | + (pc->subsampling_y << 7) | + (pc->subsampling_x << 6) | (scaling << 5) | (oh.show_frame << 4) | (oh.version << 1) | diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 49e8cce..418f60e 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1423,7 +1423,7 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) { vp9_build_block_offsets(x); - vp9_setup_block_dptrs(&x->e_mbd); + vp9_setup_block_dptrs(&x->e_mbd, cm->subsampling_x, cm->subsampling_y); xd->mode_info_context->mbmi.mode = DC_PRED; xd->mode_info_context->mbmi.uv_mode = DC_PRED; diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c index 1e25a00..ff0725f 100644 --- a/vp9/encoder/vp9_firstpass.c +++ b/vp9/encoder/vp9_firstpass.c @@ -489,7 +489,7 @@ void vp9_first_pass(VP9_COMP *cpi) { vp9_build_block_offsets(x); - vp9_setup_block_dptrs(&x->e_mbd); + vp9_setup_block_dptrs(&x->e_mbd, cm->subsampling_x, cm->subsampling_y); vp9_frame_init_quantizer(cpi); diff --git a/vp9/encoder/vp9_lookahead.c b/vp9/encoder/vp9_lookahead.c index a89d254..708fe45 100644 --- a/vp9/encoder/vp9_lookahead.c +++ b/vp9/encoder/vp9_lookahead.c @@ -46,7 +46,7 @@ void vp9_lookahead_destroy(struct lookahead_ctx *ctx) { unsigned int i; for (i = 0; i < ctx->max_sz; i++) - vp8_yv12_de_alloc_frame_buffer(&ctx->buf[i].img); + vp9_free_frame_buffer(&ctx->buf[i].img); free(ctx->buf); } free(ctx); @@ -56,6 +56,8 @@ void vp9_lookahead_destroy(struct lookahead_ctx *ctx) { struct lookahead_ctx * vp9_lookahead_init(unsigned int width, unsigned int height, + unsigned int subsampling_x, + unsigned int subsampling_y, unsigned int depth) { struct lookahead_ctx *ctx = NULL; @@ -71,8 +73,9 @@ struct lookahead_ctx * vp9_lookahead_init(unsigned int width, if (!ctx->buf) goto bail; for (i = 0; i < depth; i++) - if (vp8_yv12_alloc_frame_buffer(&ctx->buf[i].img, - width, height, VP9BORDERINPIXELS)) + if (vp9_alloc_frame_buffer(&ctx->buf[i].img, + width, height, subsampling_x, subsampling_y, + VP9BORDERINPIXELS)) goto bail; } return ctx; diff --git a/vp9/encoder/vp9_lookahead.h b/vp9/encoder/vp9_lookahead.h index 2406618..81baa2c 100644 --- a/vp9/encoder/vp9_lookahead.h +++ b/vp9/encoder/vp9_lookahead.h @@ -31,6 +31,8 @@ struct lookahead_ctx; */ struct lookahead_ctx *vp9_lookahead_init(unsigned int width, unsigned int height, + unsigned int subsampling_x, + unsigned int subsampling_y, unsigned int depth); diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 782816f..58f8fdb 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -313,9 +313,9 @@ static void dealloc_compressor_data(VP9_COMP *cpi) { vp9_free_frame_buffers(&cpi->common); - vp8_yv12_de_alloc_frame_buffer(&cpi->last_frame_uf); - vp8_yv12_de_alloc_frame_buffer(&cpi->scaled_source); - vp8_yv12_de_alloc_frame_buffer(&cpi->alt_ref_buffer); + vp9_free_frame_buffer(&cpi->last_frame_uf); + vp9_free_frame_buffer(&cpi->scaled_source); + vp9_free_frame_buffer(&cpi->alt_ref_buffer); vp9_lookahead_destroy(cpi->lookahead); vpx_free(cpi->tok); @@ -835,15 +835,19 @@ void vp9_set_speed_features(VP9_COMP *cpi) { } static void alloc_raw_frame_buffers(VP9_COMP *cpi) { + VP9_COMMON *cm = &cpi->common; + cpi->lookahead = vp9_lookahead_init(cpi->oxcf.width, cpi->oxcf.height, + cm->subsampling_x, cm->subsampling_y, cpi->oxcf.lag_in_frames); if (!cpi->lookahead) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate lag buffers"); - if (vp8_yv12_alloc_frame_buffer(&cpi->alt_ref_buffer, - cpi->oxcf.width, cpi->oxcf.height, - VP9BORDERINPIXELS)) + if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer, + cpi->oxcf.width, cpi->oxcf.height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate altref buffer"); } @@ -873,13 +877,17 @@ void vp9_alloc_compressor_data(VP9_COMP *cpi) { vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate partition data"); - if (vp8_yv12_alloc_frame_buffer(&cpi->last_frame_uf, - cm->width, cm->height, VP9BORDERINPIXELS)) + if (vp9_alloc_frame_buffer(&cpi->last_frame_uf, + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate last frame buffer"); - if (vp8_yv12_alloc_frame_buffer(&cpi->scaled_source, - cm->width, cm->height, VP9BORDERINPIXELS)) + if (vp9_alloc_frame_buffer(&cpi->scaled_source, + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to allocate scaled source buffer"); @@ -914,13 +922,17 @@ static void update_frame_size(VP9_COMP *cpi) { vp9_update_frame_size(cm); // Update size of buffers local to this frame - if (vp8_yv12_realloc_frame_buffer(&cpi->last_frame_uf, - cm->width, cm->height, VP9BORDERINPIXELS)) + if (vp9_realloc_frame_buffer(&cpi->last_frame_uf, + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to reallocate last frame buffer"); - if (vp8_yv12_realloc_frame_buffer(&cpi->scaled_source, - cm->width, cm->height, VP9BORDERINPIXELS)) + if (vp9_realloc_frame_buffer(&cpi->scaled_source, + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS)) vpx_internal_error(&cpi->common.error, VPX_CODEC_MEM_ERROR, "Failed to reallocate scaled source buffer"); @@ -1032,6 +1044,9 @@ static void init_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { cm->width = oxcf->width; cm->height = oxcf->height; + cm->subsampling_x = 0; + cm->subsampling_y = 0; + vp9_alloc_compressor_data(cpi); // change includes all joint functionality vp9_change_config(ptr, oxcf); @@ -1196,17 +1211,13 @@ void vp9_change_config(VP9_PTR ptr, VP9_CONFIG *oxcf) { cm->sharpness_level = cpi->oxcf.Sharpness; - // Increasing the size of the frame beyond the first seen frame, or some - // otherwise signalled maximum size, is not supported. - // TODO(jkoleszar): exit gracefully. - if (!cpi->initial_width) { - alloc_raw_frame_buffers(cpi); - vp9_alloc_compressor_data(cpi); - cpi->initial_width = cm->width; - cpi->initial_height = cm->height; + if (cpi->initial_width) { + // Increasing the size of the frame beyond the first seen frame, or some + // otherwise signalled maximum size, is not supported. + // TODO(jkoleszar): exit gracefully. + assert(cm->width <= cpi->initial_width); + assert(cm->height <= cpi->initial_height); } - assert(cm->width <= cpi->initial_width); - assert(cm->height <= cpi->initial_height); update_frame_size(cpi); if (cpi->oxcf.fixed_q >= 0) { @@ -2492,9 +2503,10 @@ static void scale_references(VP9_COMP *cpi) { ref->y_crop_height != cm->height) { int new_fb = get_free_fb(cm); - vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[new_fb], - cm->width, cm->height, - VP9BORDERINPIXELS); + vp9_realloc_frame_buffer(&cm->yv12_fb[new_fb], + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS); scale_and_extend_frame(ref, &cm->yv12_fb[new_fb]); cpi->scaled_ref_idx[i] = new_fb; } else { @@ -3579,6 +3591,15 @@ int vp9_receive_raw_frame(VP9_PTR ptr, unsigned int frame_flags, struct vpx_usec_timer timer; int res = 0; + if (!cpi->initial_width) { + // TODO(jkoleszar): Support 1/4 subsampling? + cm->subsampling_x = sd->uv_width < sd->y_width; + cm->subsampling_y = sd->uv_height < sd->y_height; + alloc_raw_frame_buffers(cpi); + + cpi->initial_width = cm->width; + cpi->initial_height = cm->height; + } vpx_usec_timer_start(&timer); if (vp9_lookahead_push(cpi->lookahead, sd, time_stamp, end_time, frame_flags, cpi->active_map_enabled ? cpi->active_map : NULL)) @@ -3843,9 +3864,10 @@ int vp9_get_compressed_data(VP9_PTR ptr, unsigned int *frame_flags, cm->frame_flags = *frame_flags; // Reset the frame pointers to the current frame size - vp8_yv12_realloc_frame_buffer(&cm->yv12_fb[cm->new_fb_idx], - cm->width, cm->height, - VP9BORDERINPIXELS); + vp9_realloc_frame_buffer(&cm->yv12_fb[cm->new_fb_idx], + cm->width, cm->height, + cm->subsampling_x, cm->subsampling_y, + VP9BORDERINPIXELS); // Calculate scaling factors for each of the 3 available references for (i = 0; i < ALLOWED_REFS_PER_FRAME; ++i) { diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c index 1d95eed..45609da 100644 --- a/vp9/vp9_cx_iface.c +++ b/vp9/vp9_cx_iface.c @@ -211,11 +211,12 @@ static vpx_codec_err_t validate_img(vpx_codec_alg_priv_t *ctx, switch (img->fmt) { case VPX_IMG_FMT_YV12: case VPX_IMG_FMT_I420: - case VPX_IMG_FMT_VPXI420: - case VPX_IMG_FMT_VPXYV12: + case VPX_IMG_FMT_I422: + case VPX_IMG_FMT_I444: break; default: - ERROR("Invalid image format. Only YV12 and I420 images are supported"); + ERROR("Invalid image format. Only YV12, I420, I422, I444 images are " + "supported."); } if ((img->d_w != ctx->cfg.g_w) || (img->d_h != ctx->cfg.g_h)) @@ -553,14 +554,17 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, yv12->y_crop_height = img->d_h; yv12->y_width = img->d_w; yv12->y_height = img->d_h; - yv12->uv_width = (1 + yv12->y_width) / 2; - yv12->uv_height = (1 + yv12->y_height) / 2; + + yv12->uv_width = img->x_chroma_shift == 1 ? (1 + yv12->y_width) / 2 + : yv12->y_width; + yv12->uv_height = img->y_chroma_shift == 1 ? (1 + yv12->y_height) / 2 + : yv12->y_height; yv12->y_stride = img->stride[VPX_PLANE_Y]; yv12->uv_stride = img->stride[VPX_PLANE_U]; yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2; - yv12->clrtype = (img->fmt == VPX_IMG_FMT_VPXI420 || img->fmt == VPX_IMG_FMT_VPXYV12); // REG_YUV = 0 + yv12->clrtype = REG_YUV; return res; } @@ -940,39 +944,7 @@ static vpx_image_t *vp8e_get_preview(vpx_codec_alg_priv_t *ctx) { } if (0 == vp9_get_preview_raw_frame(ctx->cpi, &sd, &flags)) { - - /* - vpx_img_wrap(&ctx->preview_img, VPX_IMG_FMT_YV12, - sd.y_width + 2*VP9BORDERINPIXELS, - sd.y_height + 2*VP9BORDERINPIXELS, - 1, - sd.buffer_alloc); - vpx_img_set_rect(&ctx->preview_img, - VP9BORDERINPIXELS, VP9BORDERINPIXELS, - sd.y_width, sd.y_height); - */ - - ctx->preview_img.bps = 12; - ctx->preview_img.planes[VPX_PLANE_Y] = sd.y_buffer; - ctx->preview_img.planes[VPX_PLANE_U] = sd.u_buffer; - ctx->preview_img.planes[VPX_PLANE_V] = sd.v_buffer; - - if (sd.clrtype == REG_YUV) - ctx->preview_img.fmt = VPX_IMG_FMT_I420; - else - ctx->preview_img.fmt = VPX_IMG_FMT_VPXI420; - - ctx->preview_img.x_chroma_shift = 1; - ctx->preview_img.y_chroma_shift = 1; - - ctx->preview_img.d_w = sd.y_width; - ctx->preview_img.d_h = sd.y_height; - ctx->preview_img.stride[VPX_PLANE_Y] = sd.y_stride; - ctx->preview_img.stride[VPX_PLANE_U] = sd.uv_stride; - ctx->preview_img.stride[VPX_PLANE_V] = sd.uv_stride; - ctx->preview_img.w = sd.y_width; - ctx->preview_img.h = sd.y_height; - + yuvconfig2image(&ctx->preview_img, &sd, NULL); return &ctx->preview_img; } else return NULL; diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h index 87d7ca6..96de5f5 100644 --- a/vp9/vp9_iface_common.h +++ b/vp9/vp9_iface_common.h @@ -16,13 +16,24 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12, * the Y, U, and V planes, nor other alignment adjustments that * might be representable by a YV12_BUFFER_CONFIG, so we just * initialize all the fields.*/ - img->fmt = yv12->clrtype == REG_YUV ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_VPXI420; + int bps = 12; + if (yv12->uv_height == yv12->y_height) { + if (yv12->uv_width == yv12->y_width) { + img->fmt = VPX_IMG_FMT_I444; + bps = 24; + } else { + img->fmt = VPX_IMG_FMT_I422; + bps = 16; + } + } else { + img->fmt = VPX_IMG_FMT_I420; + } img->w = yv12->y_stride; img->h = multiple16(yv12->y_height + 2 * VP9BORDERINPIXELS); - img->d_w = yv12->y_width; - img->d_h = yv12->y_height; - img->x_chroma_shift = 1; - img->y_chroma_shift = 1; + img->d_w = yv12->y_crop_width; + img->d_h = yv12->y_crop_height; + img->x_chroma_shift = yv12->uv_width < yv12->y_width; + img->y_chroma_shift = yv12->uv_height < yv12->y_height; img->planes[VPX_PLANE_Y] = yv12->y_buffer; img->planes[VPX_PLANE_U] = yv12->u_buffer; img->planes[VPX_PLANE_V] = yv12->v_buffer; @@ -31,7 +42,7 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12, img->stride[VPX_PLANE_U] = yv12->uv_stride; img->stride[VPX_PLANE_V] = yv12->uv_stride; img->stride[VPX_PLANE_ALPHA] = yv12->y_stride; - img->bps = 12; + img->bps = bps; img->user_priv = user_priv; img->img_data = yv12->buffer_alloc; img->img_data_owner = 0; diff --git a/vpx_scale/generic/yv12config.c b/vpx_scale/generic/yv12config.c index fc7f828..cd66f00 100644 --- a/vpx_scale/generic/yv12config.c +++ b/vpx_scale/generic/yv12config.c @@ -8,7 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ - +#include "./vpx_config.h" #include "vpx_scale/yv12config.h" #include "vpx_mem/vpx_mem.h" @@ -97,3 +97,89 @@ int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, } return -2; } + +#if CONFIG_VP9 +// TODO(jkoleszar): Maybe replace this with struct vpx_image + +int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) { + if (ybf) { + vpx_free(ybf->buffer_alloc); + + /* buffer_alloc isn't accessed by most functions. Rather y_buffer, + u_buffer and v_buffer point to buffer_alloc and are used. Clear out + all of this so that a freed pointer isn't inadvertently used */ + vpx_memset(ybf, 0, sizeof(YV12_BUFFER_CONFIG)); + } else { + return -1; + } + + return 0; +} + +int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, + int width, int height, + int ss_x, int ss_y, int border) { + if (ybf) { + const int aligned_width = (width + 15) & ~15; + const int aligned_height = (height + 15) & ~15; + const int y_stride = ((aligned_width + 2 * border) + 31) & ~31; + const int yplane_size = (aligned_height + 2 * border) * y_stride; + const int uv_width = aligned_width >> ss_x; + const int uv_height = aligned_height >> ss_y; + const int uv_stride = y_stride >> ss_x; + const int uv_border_w = border >> ss_x; + const int uv_border_h = border >> ss_y; + const int uvplane_size = (uv_height + 2 * uv_border_h) * uv_stride; + const int frame_size = yplane_size + 2 * uvplane_size; + + if (!ybf->buffer_alloc) { + ybf->buffer_alloc = vpx_memalign(32, frame_size); + ybf->buffer_alloc_sz = frame_size; + } + + if (!ybf->buffer_alloc || ybf->buffer_alloc_sz < frame_size) + return -1; + + /* Only support allocating buffers that have a border that's a multiple + * of 32. The border restriction is required to get 16-byte alignment of + * the start of the chroma rows without intoducing an arbitrary gap + * between planes, which would break the semantics of things like + * vpx_img_set_rect(). */ + if (border & 0x1f) + return -3; + + ybf->y_crop_width = width; + ybf->y_crop_height = height; + ybf->y_width = aligned_width; + ybf->y_height = aligned_height; + ybf->y_stride = y_stride; + + ybf->uv_width = uv_width; + ybf->uv_height = uv_height; + ybf->uv_stride = uv_stride; + + ybf->border = border; + ybf->frame_size = frame_size; + + ybf->y_buffer = ybf->buffer_alloc + (border * y_stride) + border; + ybf->u_buffer = ybf->buffer_alloc + yplane_size + + (uv_border_h * uv_stride) + uv_border_w; + ybf->v_buffer = ybf->buffer_alloc + yplane_size + uvplane_size + + (uv_border_h * uv_stride) + uv_border_w; + + ybf->corrupted = 0; /* assume not currupted by errors */ + return 0; + } + return -2; +} + +int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, + int width, int height, + int ss_x, int ss_y, int border) { + if (ybf) { + vp9_free_frame_buffer(ybf); + return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border); + } + return -2; +} +#endif diff --git a/vpx_scale/yv12config.h b/vpx_scale/yv12config.h index 22df399..85396c0 100644 --- a/vpx_scale/yv12config.h +++ b/vpx_scale/yv12config.h @@ -72,6 +72,14 @@ extern "C" { int width, int height, int border); int vp8_yv12_de_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf); + int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, + int width, int height, int ss_x, int ss_y, + int border); + int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, + int width, int height, int ss_x, int ss_y, + int border); + int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf); + #ifdef __cplusplus } #endif diff --git a/vpxdec.c b/vpxdec.c index 41c654f..811d41b 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -12,6 +12,7 @@ /* This is a simple program that reads ivf files and decodes them * using the new interface. Decoded frames are output as YV12 raw. */ +#include #include #include #include @@ -890,6 +891,7 @@ int main(int argc, const char **argv_) { if (use_y4m && !noblit) { char buffer[128]; + if (!single_file) { fprintf(stderr, "YUV4MPEG2 not supported with output patterns," " try --i420 or --yv12.\n"); @@ -907,8 +909,8 @@ int main(int argc, const char **argv_) { /*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.*/ - sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n", - "420jpeg", width, height, fps_num, fps_den, 'p'); + snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ", + width, height, fps_num, fps_den, 'p'); out_put(out, (unsigned char *)buffer, (unsigned int)strlen(buffer), do_md5); } @@ -1023,6 +1025,17 @@ int main(int argc, const char **argv_) { show_progress(frame_in, frame_out, dx_time); if (!noblit) { + if (frame_out == 1 && 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 (do_scale) { if (img && frame_out == 1) { stream_w = img->d_w; @@ -1031,6 +1044,7 @@ int main(int argc, const char **argv_) { stream_w, stream_h, 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], @@ -1051,6 +1065,12 @@ int main(int argc, const char **argv_) { 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; @@ -1071,15 +1091,15 @@ int main(int argc, const char **argv_) { buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U]; - for (y = 0; y < (1 + img->d_h) / 2; y++) { - out_put(out, buf, (1 + img->d_w) / 2, do_md5); + for (y = 0; y < c_h; y++) { + out_put(out, buf, c_w, do_md5); buf += img->stride[VPX_PLANE_U]; } buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V]; - for (y = 0; y < (1 + img->d_h) / 2; y++) { - out_put(out, buf, (1 + img->d_w) / 2, do_md5); + for (y = 0; y < c_h; y++) { + out_put(out, buf, c_w, do_md5); buf += img->stride[VPX_PLANE_V]; } -- 2.7.4