diff --git a/tools_common.c b/tools_common.c index 2ec17117c004a4a9c4523c052c1524fe18d901be..0d4774f1a3f46e7c325463b0a79f3854a2360203 100644 --- a/tools_common.c +++ b/tools_common.c @@ -224,7 +224,8 @@ void vpx_img_write(const vpx_image_t *img, FILE *file) { for (plane = 0; plane < 3; ++plane) { const unsigned char *buf = img->planes[plane]; const int stride = img->stride[plane]; - const int w = vpx_img_plane_width(img, plane); + const int w = vpx_img_plane_width(img, plane) * + ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); const int h = vpx_img_plane_height(img, plane); int y; diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 792e9d970b7095d76de34d3f5ccbbdc04822bc26..3954c459b641c16f26cf0ab8baffac82b236f431 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -180,6 +180,7 @@ typedef struct VP9Common { // VPX_BITS_8 in profile 0 or 1, VPX_BITS_10 or VPX_BITS_12 in profile 2 or 3. vpx_bit_depth_t bit_depth; + vpx_bit_depth_t dequant_bit_depth; // bit_depth of current dequantizer #if CONFIG_VP9_POSTPROC struct postproc_state postproc_state; diff --git a/vp9/common/vp9_reconinter.c b/vp9/common/vp9_reconinter.c index 9c4e32321d8cf8b3a6e191dc68576aeae0069c4c..1a46b39ad214121872876b5cadb37f97a1642129 100644 --- a/vp9/common/vp9_reconinter.c +++ b/vp9/common/vp9_reconinter.c @@ -467,13 +467,13 @@ static void dec_build_inter_predictors(MACROBLOCKD *xd, int plane, int block, int y1 = ((y0_16 + (h - 1) * ys) >> SUBPEL_BITS) + 1; int x_pad = 0, y_pad = 0; - if (subpel_x || (sf->x_step_q4 != 16)) { + if (subpel_x || (sf->x_step_q4 != SUBPEL_SHIFTS)) { x0 -= VP9_INTERP_EXTEND - 1; x1 += VP9_INTERP_EXTEND; x_pad = 1; } - if (subpel_y || (sf->y_step_q4 != 16)) { + if (subpel_y || (sf->y_step_q4 != SUBPEL_SHIFTS)) { y0 -= VP9_INTERP_EXTEND - 1; y1 += VP9_INTERP_EXTEND; y_pad = 1; diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 0ec271082766f142ac6c4f48c40c4846641561fd..db55de16de09a54c68de0d538fb21bc206663ca2 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -652,8 +652,10 @@ static void setup_quantization(VP9_COMMON *const cm, MACROBLOCKD *const xd, update |= read_delta_q(rb, &cm->y_dc_delta_q); update |= read_delta_q(rb, &cm->uv_dc_delta_q); update |= read_delta_q(rb, &cm->uv_ac_delta_q); - if (update) + if (update || cm->bit_depth != cm->dequant_bit_depth) { vp9_init_dequantizer(cm); + cm->dequant_bit_depth = cm->bit_depth; + } xd->lossless = cm->base_qindex == 0 && cm->y_dc_delta_q == 0 && diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index 6ee3d7037faad92d4463ba1e91bc6a5b0c8293ea..b7e1a009b824d24e4e6cc59a2f2b6da677e13c07 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -69,6 +69,7 @@ VP9Decoder *vp9_decoder_create() { cm->current_video_frame = 0; pbi->ready_for_new_data = 1; cm->bit_depth = VPX_BITS_8; + cm->dequant_bit_depth = VPX_BITS_8; // vp9_init_dequantizer() is first called here. Add check in // frame_init_dequantizer() to avoid unnecessary calling of diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index 393c66ebdad2b39a68597fe773451acf9ffa84d0..85e32d351e9d86d89cc651e9cefcc1a1dbb57198 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -437,7 +437,6 @@ static vpx_image_t *decoder_get_frame(vpx_codec_alg_priv_t *ctx, // call to get_frame. if (!(*iter)) { img = &ctx->img; - img->bit_depth = (int)ctx->pbi->common.bit_depth; *iter = img; } } diff --git a/vp9/vp9_iface_common.h b/vp9/vp9_iface_common.h index fc98b62c5e8698d5044d10aaa41362900bf21862..0398b40e84430b9899b3a02969718eda9adb50e7 100644 --- a/vp9/vp9_iface_common.h +++ b/vp9/vp9_iface_common.h @@ -46,6 +46,22 @@ 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; +#if CONFIG_VP9_HIGHBITDEPTH + if (yv12->flags & YV12_FLAG_HIGHBITDEPTH) { + // vpx_image_t uses byte strides and a pointer to the first byte + // of the image. + img->fmt |= VPX_IMG_FMT_HIGHBITDEPTH; + img->bit_depth = yv12->bit_depth; + img->planes[VPX_PLANE_Y] = (uint8_t*)CONVERT_TO_SHORTPTR(yv12->y_buffer); + img->planes[VPX_PLANE_U] = (uint8_t*)CONVERT_TO_SHORTPTR(yv12->u_buffer); + img->planes[VPX_PLANE_V] = (uint8_t*)CONVERT_TO_SHORTPTR(yv12->v_buffer); + img->planes[VPX_PLANE_ALPHA] = NULL; + img->stride[VPX_PLANE_Y] = 2 * yv12->y_stride; + img->stride[VPX_PLANE_U] = 2 * yv12->uv_stride; + img->stride[VPX_PLANE_V] = 2 * yv12->uv_stride; + img->stride[VPX_PLANE_ALPHA] = 2 * yv12->y_stride; + } +#endif // CONFIG_VP9_HIGHBITDEPTH img->bps = bps; img->user_priv = user_priv; img->img_data = yv12->buffer_alloc; @@ -72,6 +88,32 @@ static vpx_codec_err_t image2yuvconfig(const vpx_image_t *img, yv12->y_stride = img->stride[VPX_PLANE_Y]; yv12->uv_stride = img->stride[VPX_PLANE_U]; +#if CONFIG_VP9_HIGHBITDEPTH + if (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { + // In vpx_image_t + // planes point to uint8 address of start of data + // stride counts uint8s to reach next row + // In YV12_BUFFER_CONFIG + // y_buffer, u_buffer, v_buffer point to uint16 address of data + // stride and border counts in uint16s + // This means that all the address calculations in the main body of code + // should work correctly. + // However, before we do any pixel operations we need to cast the address + // to a uint16 ponter and double its value. + yv12->y_buffer = CONVERT_TO_BYTEPTR(yv12->y_buffer); + yv12->u_buffer = CONVERT_TO_BYTEPTR(yv12->u_buffer); + yv12->v_buffer = CONVERT_TO_BYTEPTR(yv12->v_buffer); + yv12->y_stride >>= 1; + yv12->uv_stride >>= 1; + yv12->flags = YV12_FLAG_HIGHBITDEPTH; + } else { + yv12->flags = 0; + } + yv12->border = (yv12->y_stride - img->w) / 2; +#else + yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2; +#endif // CONFIG_VP9_HIGHBITDEPTH + yv12->border = (img->stride[VPX_PLANE_Y] - img->w) / 2; return VPX_CODEC_OK; } diff --git a/vpxdec.c b/vpxdec.c index cf23c295e02fe99c19bfdb8b2110166ed54cce8e..f5c945c056054348336109d239fc8c0ee629b2d4 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -551,8 +551,8 @@ static void high_img_upshift(vpx_image_t *dst, vpx_image_t *src, int h = src->d_h; int x, y; if (plane) { - w >>= src->x_chroma_shift; - h >>= src->y_chroma_shift; + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; } for (y = 0; y < h; y++) { uint16_t *p_src = (uint16_t *)(src->planes[plane] + @@ -590,8 +590,8 @@ static void low_img_upshift(vpx_image_t *dst, vpx_image_t *src, int h = src->d_h; int x, y; if (plane) { - w >>= src->x_chroma_shift; - h >>= src->y_chroma_shift; + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; } for (y = 0; y < h; y++) { uint8_t *p_src = src->planes[plane] + y * src->stride[plane]; @@ -636,8 +636,8 @@ static void high_img_downshift(vpx_image_t *dst, vpx_image_t *src, int h = src->d_h; int x, y; if (plane) { - w >>= src->x_chroma_shift; - h >>= src->y_chroma_shift; + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; } for (y = 0; y < h; y++) { uint16_t *p_src = (uint16_t *)(src->planes[plane] + @@ -674,8 +674,8 @@ static void low_img_downshift(vpx_image_t *dst, vpx_image_t *src, int h = src->d_h; int x, y; if (plane) { - w >>= src->x_chroma_shift; - h >>= src->y_chroma_shift; + w = (w + src->x_chroma_shift) >> src->x_chroma_shift; + h = (h + src->y_chroma_shift) >> src->y_chroma_shift; } for (y = 0; y < h; y++) { uint16_t *p_src = (uint16_t *)(src->planes[plane] + @@ -696,6 +696,14 @@ static void img_downshift(vpx_image_t *dst, vpx_image_t *src, low_img_downshift(dst, src, down_shift); } } + +static int img_shifted_realloc_required(const vpx_image_t *img, + const vpx_image_t *shifted, + vpx_img_fmt_t required_fmt) { + return img->d_w != shifted->d_w || + img->d_h != shifted->d_h || + required_fmt != shifted->fmt; +} #endif int main_loop(int argc, const char **argv_) { @@ -1130,16 +1138,17 @@ int main_loop(int argc, const char **argv_) { } // Shift up or down if necessary if (output_bit_depth != img->bit_depth) { + const vpx_img_fmt_t shifted_fmt = output_bit_depth == 8 ? + img->fmt ^ (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) : + img->fmt | VPX_IMG_FMT_HIGHBITDEPTH; + if (img_shifted && + img_shifted_realloc_required(img, img_shifted, shifted_fmt)) { + vpx_img_free(img_shifted); + img_shifted = NULL; + } if (!img_shifted) { - if (output_bit_depth == 8) { - img_shifted = vpx_img_alloc( - NULL, img->fmt - VPX_IMG_FMT_HIGHBITDEPTH, - img->d_w, img->d_h, 16); - } else { - img_shifted = vpx_img_alloc( - NULL, img->fmt | VPX_IMG_FMT_HIGHBITDEPTH, - img->d_w, img->d_h, 16); - } + img_shifted = vpx_img_alloc(NULL, shifted_fmt, + img->d_w, img->d_h, 16); img_shifted->bit_depth = output_bit_depth; } if (output_bit_depth > img->bit_depth) {