Index: source/libvpx/vpxdec.c |
=================================================================== |
--- source/libvpx/vpxdec.c (revision 291857) |
+++ source/libvpx/vpxdec.c (working copy) |
@@ -90,12 +90,20 @@ |
static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, |
"Compute the MD5 sum of the decoded frame"); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static const arg_def_t outbitdeptharg = ARG_DEF( |
+ NULL, "output-bit-depth", 1, |
+ "Output bit-depth for decoded frames"); |
+#endif |
static const arg_def_t *all_args[] = { |
&codecarg, &use_yv12, &use_i420, &flipuvarg, &rawvideo, &noblitarg, |
&progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile, |
&threadsarg, &verbosearg, &scalearg, &fb_arg, |
&md5arg, &error_concealment, &continuearg, |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ &outbitdeptharg, |
+#endif |
NULL |
}; |
@@ -129,6 +137,26 @@ |
#if CONFIG_LIBYUV |
static INLINE int vpx_image_scale(vpx_image_t *src, vpx_image_t *dst, |
FilterModeEnum mode) { |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (src->fmt == VPX_IMG_FMT_I42016) { |
+ assert(dst->fmt == VPX_IMG_FMT_I42016); |
+ return I420Scale_16((uint16_t*)src->planes[VPX_PLANE_Y], |
+ src->stride[VPX_PLANE_Y]/2, |
+ (uint16_t*)src->planes[VPX_PLANE_U], |
+ src->stride[VPX_PLANE_U]/2, |
+ (uint16_t*)src->planes[VPX_PLANE_V], |
+ src->stride[VPX_PLANE_V]/2, |
+ src->d_w, src->d_h, |
+ (uint16_t*)dst->planes[VPX_PLANE_Y], |
+ dst->stride[VPX_PLANE_Y]/2, |
+ (uint16_t*)dst->planes[VPX_PLANE_U], |
+ dst->stride[VPX_PLANE_U]/2, |
+ (uint16_t*)dst->planes[VPX_PLANE_V], |
+ dst->stride[VPX_PLANE_V]/2, |
+ dst->d_w, dst->d_h, |
+ mode); |
+ } |
+#endif |
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], |
@@ -265,6 +293,11 @@ |
static void write_image_file(const vpx_image_t *img, const int planes[3], |
FILE *file) { |
int i, y; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ const int bytes_per_sample = ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1); |
+#else |
+ const int bytes_per_sample = 1; |
+#endif |
for (i = 0; i < 3; ++i) { |
const int plane = planes[i]; |
@@ -274,7 +307,7 @@ |
const int h = vpx_img_plane_height(img, plane); |
for (y = 0; y < h; ++y) { |
- fwrite(buf, 1, w, file); |
+ fwrite(buf, bytes_per_sample, w, file); |
buf += stride; |
} |
} |
@@ -494,6 +527,178 @@ |
} |
} |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+static void high_img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ const int offset = input_shift > 0 ? (1 << (input_shift - 1)) : 0; |
+ int plane; |
+ if (dst->d_w != src->d_w || dst->d_h != src->d_h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ dst->fmt != src->fmt || input_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (src->fmt) { |
+ case VPX_IMG_FMT_I42016: |
+ case VPX_IMG_FMT_I42216: |
+ case VPX_IMG_FMT_I44416: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->d_w; |
+ int h = src->d_h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint16_t *p_src = (uint16_t *)(src->planes[plane] + |
+ y * src->stride[plane]); |
+ uint16_t *p_dst = (uint16_t *)(dst->planes[plane] + |
+ y * dst->stride[plane]); |
+ for (x = 0; x < w; x++) |
+ *p_dst++ = (*p_src++ << input_shift) + offset; |
+ } |
+ } |
+} |
+ |
+static void low_img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ const int offset = input_shift > 0 ? (1 << (input_shift - 1)) : 0; |
+ int plane; |
+ if (dst->d_w != src->d_w || dst->d_h != src->d_h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ dst->fmt != src->fmt + VPX_IMG_FMT_HIGHBITDEPTH || |
+ input_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (src->fmt) { |
+ case VPX_IMG_FMT_I420: |
+ case VPX_IMG_FMT_I422: |
+ case VPX_IMG_FMT_I444: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->d_w; |
+ int h = src->d_h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint8_t *p_src = src->planes[plane] + y * src->stride[plane]; |
+ uint16_t *p_dst = (uint16_t *)(dst->planes[plane] + |
+ y * dst->stride[plane]); |
+ for (x = 0; x < w; x++) { |
+ *p_dst++ = (*p_src++ << input_shift) + offset; |
+ } |
+ } |
+ } |
+} |
+ |
+static void img_upshift(vpx_image_t *dst, vpx_image_t *src, |
+ int input_shift) { |
+ if (src->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ high_img_upshift(dst, src, input_shift); |
+ } else { |
+ low_img_upshift(dst, src, input_shift); |
+ } |
+} |
+ |
+static void high_img_downshift(vpx_image_t *dst, vpx_image_t *src, |
+ int down_shift) { |
+ int plane; |
+ if (dst->d_w != src->d_w || dst->d_h != src->d_h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ dst->fmt != src->fmt || down_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (src->fmt) { |
+ case VPX_IMG_FMT_I42016: |
+ case VPX_IMG_FMT_I42216: |
+ case VPX_IMG_FMT_I44416: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->d_w; |
+ int h = src->d_h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint16_t *p_src = (uint16_t *)(src->planes[plane] + |
+ y * src->stride[plane]); |
+ uint16_t *p_dst = (uint16_t *)(dst->planes[plane] + |
+ y * dst->stride[plane]); |
+ for (x = 0; x < w; x++) |
+ *p_dst++ = *p_src++ >> down_shift; |
+ } |
+ } |
+} |
+ |
+static void low_img_downshift(vpx_image_t *dst, vpx_image_t *src, |
+ int down_shift) { |
+ int plane; |
+ if (dst->d_w != src->d_w || dst->d_h != src->d_h || |
+ dst->x_chroma_shift != src->x_chroma_shift || |
+ dst->y_chroma_shift != src->y_chroma_shift || |
+ src->fmt != dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH || |
+ down_shift < 0) { |
+ fatal("Unsupported image conversion"); |
+ } |
+ switch (dst->fmt) { |
+ case VPX_IMG_FMT_I420: |
+ case VPX_IMG_FMT_I422: |
+ case VPX_IMG_FMT_I444: |
+ break; |
+ default: |
+ fatal("Unsupported image conversion"); |
+ break; |
+ } |
+ for (plane = 0; plane < 3; plane++) { |
+ int w = src->d_w; |
+ int h = src->d_h; |
+ int x, y; |
+ if (plane) { |
+ w >>= src->x_chroma_shift; |
+ h >>= src->y_chroma_shift; |
+ } |
+ for (y = 0; y < h; y++) { |
+ uint16_t *p_src = (uint16_t *)(src->planes[plane] + |
+ y * src->stride[plane]); |
+ uint8_t *p_dst = dst->planes[plane] + y * dst->stride[plane]; |
+ for (x = 0; x < w; x++) { |
+ *p_dst++ = *p_src++ >> down_shift; |
+ } |
+ } |
+ } |
+} |
+ |
+static void img_downshift(vpx_image_t *dst, vpx_image_t *src, |
+ int down_shift) { |
+ if (dst->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { |
+ high_img_downshift(dst, src, down_shift); |
+ } else { |
+ low_img_downshift(dst, src, down_shift); |
+ } |
+} |
+#endif |
+ |
int main_loop(int argc, const char **argv_) { |
vpx_codec_ctx_t decoder; |
char *fn = NULL; |
@@ -518,6 +723,9 @@ |
int opt_yv12 = 0; |
int opt_i420 = 0; |
vpx_codec_dec_cfg_t cfg = {0, 0, 0}; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ int output_bit_depth = 0; |
+#endif |
#if CONFIG_VP8_DECODER |
vp8_postproc_cfg_t vp8_pp_cfg = {0}; |
int vp8_dbg_color_ref_frame = 0; |
@@ -529,6 +737,9 @@ |
int dec_flags = 0; |
int do_scale = 0; |
vpx_image_t *scaled_img = NULL; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ vpx_image_t *img_shifted = NULL; |
+#endif |
int frame_avail, got_data; |
int num_external_frame_buffers = 0; |
struct ExternalFrameBufferList ext_fb_list = {0, NULL}; |
@@ -569,6 +780,9 @@ |
use_y4m = 0; |
flipuv = 1; |
opt_yv12 = 1; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ output_bit_depth = 8; // For yv12 8-bit depth output is assumed |
+#endif |
} else if (arg_match(&arg, &use_i420, argi)) { |
use_y4m = 0; |
flipuv = 0; |
@@ -599,7 +813,13 @@ |
do_scale = 1; |
else if (arg_match(&arg, &fb_arg, argi)) |
num_external_frame_buffers = arg_parse_uint(&arg); |
- |
+ else if (arg_match(&arg, &continuearg, argi)) |
+ keep_going = 1; |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ else if (arg_match(&arg, &outbitdeptharg, argi)) { |
+ output_bit_depth = arg_parse_uint(&arg); |
+ } |
+#endif |
#if CONFIG_VP8_DECODER |
else if (arg_match(&arg, &addnoise_level, argi)) { |
postproc = 1; |
@@ -649,11 +869,8 @@ |
} |
} else if (arg_match(&arg, &error_concealment, argi)) { |
ec_enabled = 1; |
- } else if (arg_match(&arg, &continuearg, argi)) { |
- keep_going = 1; |
} |
- |
-#endif |
+#endif // CONFIG_VP8_DECODER |
else |
argj++; |
} |
@@ -889,7 +1106,7 @@ |
display_height = display_size[1]; |
} |
} |
- scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, display_width, |
+ scaled_img = vpx_img_alloc(NULL, img->fmt, display_width, |
display_height, 16); |
scaled_img->bit_depth = img->bit_depth; |
} |
@@ -907,6 +1124,33 @@ |
#endif |
} |
} |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ // Default to codec bit depth if output bit depth not set |
+ if (!output_bit_depth) { |
+ output_bit_depth = img->bit_depth; |
+ } |
+ // Shift up or down if necessary |
+ if (output_bit_depth != img->bit_depth) { |
+ 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->bit_depth = output_bit_depth; |
+ } |
+ if (output_bit_depth > img->bit_depth) { |
+ img_upshift(img_shifted, img, output_bit_depth - img->bit_depth); |
+ } else { |
+ img_downshift(img_shifted, img, img->bit_depth - output_bit_depth); |
+ } |
+ img = img_shifted; |
+ } |
+#endif |
if (single_file) { |
if (use_y4m) { |
@@ -1013,6 +1257,9 @@ |
free(buf); |
if (scaled_img) vpx_img_free(scaled_img); |
+#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH |
+ if (img_shifted) vpx_img_free(img_shifted); |
+#endif |
for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) { |
free(ext_fb_list.ext_fb[i].data); |