Adds config opt for highbitdepth + misc. vpx

Adds config parameter vp9_highbitdepth, to support highbitdepth profiles.
Also includes most vpx level high bit-depth functions. However
encode/decode in the highbitdepth profiles will not work until
the rest of the code is in place.

Change-Id: I34c53b253c38873611057a6cbc89a1361b8985a6
This commit is contained in:
Deb Mukherjee 2014-08-26 12:35:15 -07:00
Родитель 72037944df
Коммит 5acfafb18e
33 изменённых файлов: 1106 добавлений и 57 удалений

2
configure поставляемый
Просмотреть файл

@ -334,6 +334,7 @@ CONFIG_LIST="
multi_res_encoding
temporal_denoising
coefficient_range_checking
vp9_highbitdepth
experimental
size_limit
${EXPERIMENT_LIST}
@ -392,6 +393,7 @@ CMDLINE_SELECT="
multi_res_encoding
temporal_denoising
coefficient_range_checking
vp9_highbitdepth
experimental
"

Просмотреть файл

@ -28,7 +28,8 @@ class MD5 {
// plane, we never want to round down and thus skip a pixel so if
// we are shifting by 1 (chroma_shift) we add 1 before doing the shift.
// This works only for chroma_shift of 0 and 1.
const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
const int bytes_per_sample =
(img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
const int h = plane ? (img->d_h + img->y_chroma_shift) >>
img->y_chroma_shift : img->d_h;
const int w = (plane ? (img->d_w + img->x_chroma_shift) >>

Просмотреть файл

@ -57,7 +57,7 @@ static void write_image_file(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 bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
const int h = (plane ? (img->d_h + img->y_chroma_shift) >>
img->y_chroma_shift : img->d_h);
const int w = (plane ? (img->d_w + img->x_chroma_shift) >>

Просмотреть файл

@ -83,7 +83,7 @@ int read_yuv_frame(struct VpxInputContext *input_ctx, vpx_image_t *yuv_frame) {
struct FileTypeDetectionBuffer *detect = &input_ctx->detect;
int plane = 0;
int shortread = 0;
const int bytespp = (yuv_frame->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
const int bytespp = (yuv_frame->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1;
for (plane = 0; plane < 3; ++plane) {
uint8_t *ptr;
@ -241,7 +241,8 @@ int vpx_img_read(vpx_image_t *img, FILE *file) {
for (plane = 0; plane < 3; ++plane) {
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;

Просмотреть файл

@ -1244,6 +1244,9 @@ static vpx_codec_enc_cfg_map_t vp8e_usage_cfg_map[] =
320, /* g_width */
240, /* g_height */
VPX_BITS_8, /* g_bit_depth */
8, /* g_input_bit_depth */
{1, 30}, /* g_timebase */
0, /* g_error_resilient */

Просмотреть файл

@ -177,7 +177,11 @@ int vp9_alloc_ref_frame_buffers(VP9_COMMON *cm, int width, int height) {
for (i = 0; i < FRAME_BUFFERS; ++i) {
cm->frame_bufs[i].ref_count = 0;
if (vp9_alloc_frame_buffer(&cm->frame_bufs[i].buf, width, height,
ss_x, ss_y, VP9_ENC_BORDER_IN_PIXELS) < 0)
ss_x, ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail;
}
@ -185,6 +189,9 @@ int vp9_alloc_ref_frame_buffers(VP9_COMMON *cm, int width, int height) {
#if CONFIG_INTERNAL_STATS || CONFIG_VP9_POSTPROC
if (vp9_alloc_frame_buffer(&cm->post_proc_buffer, width, height, ss_x, ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS) < 0)
goto fail;
#endif

Просмотреть файл

@ -64,6 +64,11 @@ static INLINE int get_unsigned_bits(unsigned int num_values) {
return num_values > 0 ? get_msb(num_values) + 1 : 0;
}
#if CONFIG_VP9_HIGHBITDEPTH
#define CONVERT_TO_SHORTPTR(x) ((uint16_t*)(((uintptr_t)x) << 1))
#define CONVERT_TO_BYTEPTR(x) ((uint8_t*)(((uintptr_t)x) >> 1 ))
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_DEBUG
#define CHECK_MEM_ERROR(cm, lval, expr) do { \
lval = (expr); \

Просмотреть файл

@ -40,12 +40,6 @@ typedef enum BITSTREAM_PROFILE {
MAX_PROFILES
} BITSTREAM_PROFILE;
typedef enum BIT_DEPTH {
BITS_8,
BITS_10,
BITS_12
} BIT_DEPTH;
typedef enum BLOCK_SIZE {
BLOCK_4X4,
BLOCK_4X8,

Просмотреть файл

@ -84,6 +84,10 @@ typedef struct VP9Common {
int subsampling_x;
int subsampling_y;
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth; // Marks if we need to use 16bit frame buffers.
#endif
YV12_BUFFER_CONFIG *frame_to_show;
RefCntBuffer frame_bufs[FRAME_BUFFERS];
@ -179,8 +183,8 @@ typedef struct VP9Common {
unsigned int current_video_frame;
BITSTREAM_PROFILE profile;
// BITS_8 in versions 0 and 1, BITS_10 or BITS_12 in version 2
BIT_DEPTH bit_depth;
// 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;
#if CONFIG_VP9_POSTPROC
struct postproc_state postproc_state;

Просмотреть файл

@ -653,7 +653,11 @@ static void setup_frame_size(VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) {
if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_DEC_BORDER_IN_PIXELS,
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer, cm->get_fb_cb,
cm->cb_priv)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
@ -700,7 +704,11 @@ static void setup_frame_size_with_refs(VP9_COMMON *cm,
if (vp9_realloc_frame_buffer(
get_frame_new_buffer(cm), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y, VP9_DEC_BORDER_IN_PIXELS,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_DEC_BORDER_IN_PIXELS,
&cm->frame_bufs[cm->new_fb_idx].raw_frame_buffer, cm->get_fb_cb,
cm->cb_priv)) {
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
@ -1100,7 +1108,7 @@ BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb) {
static void read_bitdepth_colorspace_sampling(
VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) {
if (cm->profile >= PROFILE_2)
cm->bit_depth = vp9_rb_read_bit(rb) ? BITS_12 : BITS_10;
cm->bit_depth = vp9_rb_read_bit(rb) ? VPX_BITS_12 : VPX_BITS_10;
cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3);
if (cm->color_space != SRGB) {
vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range
@ -1144,6 +1152,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
"Invalid frame marker");
cm->profile = vp9_read_profile(rb);
if (cm->profile >= MAX_PROFILES)
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
"Unsupported bitstream profile");
@ -1402,7 +1411,7 @@ void vp9_decode_frame(VP9Decoder *pbi,
if (!first_partition_size) {
// showing a frame directly
*p_data_end = data + 1;
*p_data_end = data + (cm->profile <= PROFILE_2 ? 1 : 2);
return;
}

Просмотреть файл

@ -66,6 +66,7 @@ VP9Decoder *vp9_decoder_create() {
cm->current_video_frame = 0;
pbi->ready_for_new_data = 1;
cm->bit_depth = VPX_BITS_8;
// vp9_init_dequantizer() is first called here. Add check in
// frame_init_dequantizer() to avoid unnecessary calling of

Просмотреть файл

@ -1046,8 +1046,8 @@ static void write_profile(BITSTREAM_PROFILE profile,
static void write_bitdepth_colorspace_sampling(
VP9_COMMON *const cm, struct vp9_write_bit_buffer *wb) {
if (cm->profile >= PROFILE_2) {
assert(cm->bit_depth > BITS_8);
vp9_wb_write_bit(wb, cm->bit_depth - BITS_10);
assert(cm->bit_depth > VPX_BITS_8);
vp9_wb_write_bit(wb, cm->bit_depth == VPX_BITS_10 ? 0 : 1);
}
vp9_wb_write_literal(wb, cm->color_space, 3);
if (cm->color_space != SRGB) {

Просмотреть файл

@ -388,13 +388,21 @@ void vp9_denoiser_update_frame_stats(MB_MODE_INFO *mbmi, unsigned int sse,
}
int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height,
int ssx, int ssy, int border) {
int ssx, int ssy,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border) {
int i, fail;
assert(denoiser != NULL);
for (i = 0; i < MAX_REF_FRAMES; ++i) {
fail = vp9_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height,
ssx, ssy, border);
ssx, ssy,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
border);
if (fail) {
vp9_denoiser_free(denoiser);
return 1;
@ -405,7 +413,11 @@ int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height,
}
fail = vp9_alloc_frame_buffer(&denoiser->mc_running_avg_y, width, height,
ssx, ssy, border);
ssx, ssy,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
border);
if (fail) {
vp9_denoiser_free(denoiser);
return 1;

Просмотреть файл

@ -47,7 +47,11 @@ void vp9_denoiser_update_frame_stats(MB_MODE_INFO *mbmi,
PICK_MODE_CONTEXT *ctx);
int vp9_denoiser_alloc(VP9_DENOISER *denoiser, int width, int height,
int ssx, int ssy, int border);
int ssx, int ssy,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border);
void vp9_denoiser_free(VP9_DENOISER *denoiser);

Просмотреть файл

@ -443,6 +443,9 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
cpi->lookahead = vp9_lookahead_init(oxcf->width, oxcf->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
oxcf->lag_in_frames);
if (!cpi->lookahead)
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
@ -451,6 +454,9 @@ static void alloc_raw_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
oxcf->width, oxcf->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate altref buffer");
@ -468,6 +474,9 @@ static void alloc_util_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->last_frame_uf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate last frame buffer");
@ -475,6 +484,9 @@ static void alloc_util_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->scaled_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled source buffer");
@ -482,6 +494,9 @@ static void alloc_util_frame_buffers(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->scaled_last_source,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to allocate scaled last source buffer");
@ -514,6 +529,9 @@ static void update_frame_size(VP9_COMP *cpi) {
if (vp9_realloc_frame_buffer(&cpi->alt_ref_buffer,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,
"Failed to reallocate alt_ref_buffer");
@ -600,9 +618,9 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
cm->bit_depth = oxcf->bit_depth;
if (cm->profile <= PROFILE_1)
assert(cm->bit_depth == BITS_8);
assert(cm->bit_depth == VPX_BITS_8);
else
assert(cm->bit_depth > BITS_8);
assert(cm->bit_depth > VPX_BITS_8);
cpi->oxcf = *oxcf;
@ -677,6 +695,9 @@ void vp9_change_config(struct VP9_COMP *cpi, const VP9EncoderConfig *oxcf) {
if (cpi->oxcf.noise_sensitivity > 0) {
vp9_denoiser_alloc(&(cpi->denoiser), cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS);
}
#endif
@ -1604,6 +1625,9 @@ void vp9_scale_references(VP9_COMP *cpi) {
vp9_realloc_frame_buffer(&cm->frame_bufs[new_fb].buf,
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
scale_and_extend_frame(ref, &cm->frame_bufs[new_fb].buf);
cpi->scaled_ref_idx[ref_frame - 1] = new_fb;
@ -2699,6 +2723,9 @@ int vp9_get_compressed_data(VP9_COMP *cpi, unsigned int *frame_flags,
vp9_realloc_frame_buffer(get_frame_new_buffer(cm),
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL, NULL);
alloc_util_frame_buffers(cpi);

Просмотреть файл

@ -114,9 +114,10 @@ typedef enum {
typedef struct VP9EncoderConfig {
BITSTREAM_PROFILE profile;
BIT_DEPTH bit_depth;
vpx_bit_depth_t bit_depth; // Codec bit-depth.
int width; // width of data passed to the compressor
int height; // height of data passed to the compressor
unsigned int input_bit_depth; // Input bit depth.
double init_framerate; // set to passed in framerate
int64_t target_bandwidth; // bandwidth to be used in kilobits per second

Просмотреть файл

@ -50,6 +50,9 @@ struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
unsigned int height,
unsigned int subsampling_x,
unsigned int subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int depth) {
struct lookahead_ctx *ctx = NULL;
@ -70,6 +73,9 @@ struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
for (i = 0; i < depth; i++)
if (vp9_alloc_frame_buffer(&ctx->buf[i].img,
width, height, subsampling_x, subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS))
goto bail;
}

Просмотреть файл

@ -56,6 +56,9 @@ struct lookahead_ctx *vp9_lookahead_init(unsigned int width,
unsigned int height,
unsigned int subsampling_x,
unsigned int subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
unsigned int depth);

Просмотреть файл

@ -465,6 +465,9 @@ void vp9_temporal_filter(VP9_COMP *cpi, int distance) {
if (vp9_realloc_frame_buffer(&cpi->svc.scaled_frames[frame_used],
cm->width, cm->height,
cm->subsampling_x, cm->subsampling_y,
#if CONFIG_VP9_HIGHBITDEPTH
cm->use_highbitdepth,
#endif
VP9_ENC_BORDER_IN_PIXELS, NULL, NULL,
NULL))
vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR,

Просмотреть файл

@ -37,7 +37,7 @@ struct vp9_extracfg {
unsigned int frame_parallel_decoding_mode;
AQ_MODE aq_mode;
unsigned int frame_periodic_boost;
BIT_DEPTH bit_depth;
vpx_bit_depth_t bit_depth;
vp9e_tune_content content;
};
@ -58,7 +58,7 @@ static struct vp9_extracfg default_extra_cfg = {
0, // frame_parallel_decoding_mode
NO_AQ, // aq_mode
0, // frame_periodic_delta_q
BITS_8, // Bit depth
VPX_BITS_8, // Bit depth
VP9E_CONTENT_DEFAULT // content
};
@ -208,6 +208,8 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK(extra_cfg, arnr_max_frames, 0, 15);
RANGE_CHECK_HI(extra_cfg, arnr_strength, 6);
RANGE_CHECK(extra_cfg, cq_level, 0, 63);
RANGE_CHECK(cfg, g_bit_depth, VPX_BITS_8, VPX_BITS_12);
RANGE_CHECK(cfg, g_input_bit_depth, 8, 12);
RANGE_CHECK(extra_cfg, content,
VP9E_CONTENT_DEFAULT, VP9E_CONTENT_INVALID - 1);
@ -266,12 +268,16 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
}
}
#if !CONFIG_VP9_HIGHBITDEPTH
if (cfg->g_profile > (unsigned int)PROFILE_1)
ERROR("Profile > 1 not supported in this build configuration");
#endif
if (cfg->g_profile <= (unsigned int)PROFILE_1 &&
extra_cfg->bit_depth > BITS_8)
ERROR("High bit-depth not supported in profile < 2");
extra_cfg->bit_depth > VPX_BITS_8)
ERROR("Codec high bit-depth not supported in profile < 2");
if (cfg->g_profile > (unsigned int)PROFILE_1 &&
extra_cfg->bit_depth == BITS_8)
ERROR("Bit-depth 8 not supported in profile > 1");
extra_cfg->bit_depth == VPX_BITS_8)
ERROR("Codec bit-depth 8 not supported in profile > 1");
return VPX_CODEC_OK;
}
@ -303,6 +309,9 @@ static int get_image_bps(const vpx_image_t *img) {
case VPX_IMG_FMT_I420: return 12;
case VPX_IMG_FMT_I422: return 16;
case VPX_IMG_FMT_I444: return 24;
case VPX_IMG_FMT_I42016: return 24;
case VPX_IMG_FMT_I42216: return 32;
case VPX_IMG_FMT_I44416: return 48;
default: assert(0 && "Invalid image format"); break;
}
return 0;
@ -317,6 +326,7 @@ static vpx_codec_err_t set_encoder_config(
oxcf->width = cfg->g_w;
oxcf->height = cfg->g_h;
oxcf->bit_depth = extra_cfg->bit_depth;
oxcf->input_bit_depth = cfg->g_input_bit_depth;
// guess a frame rate if out of whack, use 30
oxcf->init_framerate = (double)cfg->g_timebase.den / cfg->g_timebase.num;
if (oxcf->init_framerate > 180)
@ -1246,6 +1256,9 @@ static vpx_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
320, // g_width
240, // g_height
VPX_BITS_8, // g_bit_depth
8, // g_input_bit_depth
{1, 30}, // g_timebase
0, // g_error_resilient

Просмотреть файл

@ -440,6 +440,7 @@ 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;
}
}
@ -588,6 +589,23 @@ static vpx_codec_err_t ctrl_get_display_size(vpx_codec_alg_priv_t *ctx,
}
}
static vpx_codec_err_t ctrl_get_bit_depth(vpx_codec_alg_priv_t *ctx,
va_list args) {
unsigned int *const bit_depth = va_arg(args, unsigned int *);
if (bit_depth) {
if (ctx->pbi) {
const VP9_COMMON *const cm = &ctx->pbi->common;
*bit_depth = cm->bit_depth;
return VPX_CODEC_OK;
} else {
return VPX_CODEC_ERROR;
}
} else {
return VPX_CODEC_INVALID_PARAM;
}
}
static vpx_codec_err_t ctrl_set_invert_tile_order(vpx_codec_alg_priv_t *ctx,
va_list args) {
ctx->invert_tile_order = va_arg(args, int);
@ -620,6 +638,7 @@ static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = {
{VP8D_GET_FRAME_CORRUPTED, ctrl_get_frame_corrupted},
{VP9_GET_REFERENCE, ctrl_get_reference},
{VP9D_GET_DISPLAY_SIZE, ctrl_get_display_size},
{VP9D_GET_BIT_DEPTH, ctrl_get_bit_depth},
{ -1, NULL},
};

Просмотреть файл

@ -154,7 +154,7 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img,
goto fail;
img->fmt = fmt;
img->bit_depth = (fmt & VPX_IMG_FMT_HIGH) ? 16 : 8;
img->bit_depth = (fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
img->w = w;
img->h = h;
img->x_chroma_shift = xcs;

Просмотреть файл

@ -75,6 +75,9 @@ enum vp8_dec_control_id {
/** control function to get the display dimensions for the current frame. */
VP9D_GET_DISPLAY_SIZE,
/** control function to get the bit depth of the stream. */
VP9D_GET_BIT_DEPTH,
/** For testing. */
VP9_INVERT_TILE_DECODE_ORDER,
@ -118,6 +121,7 @@ VPX_CTRL_USE_TYPE(VP8D_GET_LAST_REF_USED, int *)
VPX_CTRL_USE_TYPE(VPXD_SET_DECRYPTOR, vpx_decrypt_init *)
VPX_CTRL_USE_TYPE(VP8D_SET_DECRYPTOR, vpx_decrypt_init *)
VPX_CTRL_USE_TYPE(VP9D_GET_DISPLAY_SIZE, int *)
VPX_CTRL_USE_TYPE(VP9D_GET_BIT_DEPTH, unsigned int *)
VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int)
/*! @} - end defgroup vp8_decoder */

Просмотреть файл

@ -217,9 +217,9 @@ extern "C" {
* This enumeration determines the bit depth of the codec.
*/
typedef enum vpx_bit_depth {
VPX_BITS_8, /**< 8 bits */
VPX_BITS_10, /**< 10 bits */
VPX_BITS_12 /**< 12 bits */
VPX_BITS_8 = 8, /**< 8 bits */
VPX_BITS_10 = 10, /**< 10 bits */
VPX_BITS_12 = 12, /**< 12 bits */
} vpx_bit_depth_t;
/*

Просмотреть файл

@ -80,6 +80,9 @@ extern "C" {
*/
#define VPX_CODEC_CAP_OUTPUT_PARTITION 0x20000
/*! Can support input images at greater than 8 bitdepth.
*/
#define VPX_CODEC_CAP_HIGHBITDEPTH 0x40000
/*! \brief Initialization-time Feature Enabling
*
@ -91,6 +94,7 @@ extern "C" {
#define VPX_CODEC_USE_PSNR 0x10000 /**< Calculate PSNR on each frame */
#define VPX_CODEC_USE_OUTPUT_PARTITION 0x20000 /**< Make the encoder output one
partition at a time. */
#define VPX_CODEC_USE_HIGHBITDEPTH 0x40000 /**< Use high bitdepth */
/*!\brief Generic fixed size buffer structure
@ -324,6 +328,21 @@ extern "C" {
*/
unsigned int g_h;
/*!\brief Bit-depth of the codec
*
* This value identifies the bit_depth of the codec,
* Only certain bit-depths are supported as identified in the
* vpx_bit_depth_t enum.
*/
vpx_bit_depth_t g_bit_depth;
/*!\brief Bit-depth of the input frames
*
* This value identifies the bit_depth of the input frames in bits.
* Note that the frames passed as input to the encoder must have
* this bit-depth.
*/
unsigned int g_input_bit_depth;
/*!\brief Stream timebase units
*

Просмотреть файл

@ -31,10 +31,10 @@ extern "C" {
#define VPX_IMAGE_ABI_VERSION (2) /**<\hideinitializer*/
#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format */
#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U plane in memory */
#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel component */
#define VPX_IMG_FMT_HIGH 0x800 /**< Image uses 16bit framebuffer */
#define VPX_IMG_FMT_PLANAR 0x100 /**< Image is a planar format. */
#define VPX_IMG_FMT_UV_FLIP 0x200 /**< V plane precedes U in memory. */
#define VPX_IMG_FMT_HAS_ALPHA 0x400 /**< Image has an alpha channel. */
#define VPX_IMG_FMT_HIGHBITDEPTH 0x800 /**< Image uses 16bit framebuffer. */
/*!\brief List of supported image formats */
typedef enum vpx_img_fmt {
@ -59,9 +59,9 @@ extern "C" {
VPX_IMG_FMT_I422 = VPX_IMG_FMT_PLANAR | 5,
VPX_IMG_FMT_I444 = VPX_IMG_FMT_PLANAR | 6,
VPX_IMG_FMT_444A = VPX_IMG_FMT_PLANAR | VPX_IMG_FMT_HAS_ALPHA | 7,
VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGH,
VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGH,
VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGH
VPX_IMG_FMT_I42016 = VPX_IMG_FMT_I420 | VPX_IMG_FMT_HIGHBITDEPTH,
VPX_IMG_FMT_I42216 = VPX_IMG_FMT_I422 | VPX_IMG_FMT_HIGHBITDEPTH,
VPX_IMG_FMT_I44416 = VPX_IMG_FMT_I444 | VPX_IMG_FMT_HIGHBITDEPTH
} vpx_img_fmt_t; /**< alias for enum vpx_img_fmt */
#if !defined(VPX_CODEC_DISABLE_COMPAT) || !VPX_CODEC_DISABLE_COMPAT

Просмотреть файл

@ -16,6 +16,7 @@
#include <stdlib.h>
#include <string.h>
#include "include/vpx_mem_intrnl.h"
#include "vpx/vpx_integer.h"
#if CONFIG_MEM_TRACKER
#ifndef VPX_NO_GLOBALS
@ -452,6 +453,29 @@ void *vpx_memset(void *dest, int val, size_t length) {
return VPX_MEMSET_L(dest, val, length);
}
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
void *vpx_memset16(void *dest, int val, size_t length) {
#if CONFIG_MEM_CHECKS
if ((int)dest < 0x4000) {
_P(printf("WARNING: vpx_memset dest:0x%x val:%d len:%d\n",
(int)dest, val, length);)
#if defined(VXWORKS)
sp(get_my_tt, task_id_self(), 0, 0, 0, 0, 0, 0, 0, 0);
vx_sleep(10000);
#endif
}
#endif
int i;
void *orig = dest;
uint16_t *dest16 = dest;
for (i = 0; i < length; i++)
*dest16++ = val;
return orig;
}
#endif // CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
void *vpx_memmove(void *dest, const void *src, size_t count) {
#if CONFIG_MEM_CHECKS

Просмотреть файл

@ -73,6 +73,9 @@ extern "C" {
void *vpx_memcpy(void *dest, const void *src, size_t length);
void *vpx_memset(void *dest, int val, size_t length);
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
void *vpx_memset16(void *dest, int val, size_t length);
#endif
void *vpx_memmove(void *dest, const void *src, size_t count);
/* special memory functions */

Просмотреть файл

@ -13,6 +13,9 @@
#include "./vpx_config.h"
#include "vpx_scale/yv12config.h"
#include "vpx_mem/vpx_mem.h"
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
#include "vp9/common/vp9_common.h"
#endif
/****************************************************************************
* Exports
@ -136,7 +139,11 @@ int vp9_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height,
int ss_x, int ss_y, int border,
int ss_x, int ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border,
vpx_codec_frame_buffer_t *fb,
vpx_get_frame_buffer_cb_fn_t cb,
void *cb_priv) {
@ -161,11 +168,21 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
const int alpha_border_h = border;
const uint64_t alpha_plane_size = (alpha_height + 2 * alpha_border_h) *
(uint64_t)alpha_stride;
#if CONFIG_VP9_HIGHBITDEPTH
const uint64_t frame_size = (1 + use_highbitdepth) *
(yplane_size + 2 * uvplane_size + alpha_plane_size);
#else
const uint64_t frame_size = yplane_size + 2 * uvplane_size +
alpha_plane_size;
#endif // CONFIG_VP9_HIGHBITDEPTH
#else
#if CONFIG_VP9_HIGHBITDEPTH
const uint64_t frame_size =
(1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size);
#else
const uint64_t frame_size = yplane_size + 2 * uvplane_size;
#endif
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_ALPHA
if (cb != NULL) {
const int align_addr_extra_size = 31;
const uint64_t external_frame_size = frame_size + align_addr_extra_size;
@ -231,11 +248,31 @@ int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
ybf->border = border;
ybf->frame_size = (int)frame_size;
#if CONFIG_VP9_HIGHBITDEPTH
if (use_highbitdepth) {
// Store uint16 addresses when using 16bit framebuffers
uint8_t *p = CONVERT_TO_BYTEPTR(ybf->buffer_alloc);
ybf->y_buffer = p + (border * y_stride) + border;
ybf->u_buffer = p + yplane_size +
(uv_border_h * uv_stride) + uv_border_w;
ybf->v_buffer = p + yplane_size + uvplane_size +
(uv_border_h * uv_stride) + uv_border_w;
ybf->flags = YV12_FLAG_HIGHBITDEPTH;
} else {
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->flags = 0;
}
#else
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;
#endif // CONFIG_VP9_HIGHBITDEPTH
#if CONFIG_ALPHA
ybf->alpha_width = alpha_width;
@ -252,11 +289,18 @@ int vp9_realloc_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 ss_x, int ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border) {
if (ybf) {
vp9_free_frame_buffer(ybf);
return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y, border,
NULL, NULL, NULL);
return vp9_realloc_frame_buffer(ybf, width, height, ss_x, ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
use_highbitdepth,
#endif
border, NULL, NULL, NULL);
}
return -2;
}

Просмотреть файл

@ -13,6 +13,9 @@
#include "vpx/vpx_integer.h"
#include "vpx_mem/vpx_mem.h"
#include "vpx_scale/yv12config.h"
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
#include "vp9/common/vp9_common.h"
#endif
static void extend_plane(uint8_t *const src, int src_stride,
int width, int height,
@ -55,6 +58,50 @@ static void extend_plane(uint8_t *const src, int src_stride,
}
}
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static void extend_plane_high(uint8_t *const src8, int src_stride,
int width, int height,
int extend_top, int extend_left,
int extend_bottom, int extend_right) {
int i;
const int linesize = extend_left + extend_right + width;
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
/* copy the left and right most columns out */
uint16_t *src_ptr1 = src;
uint16_t *src_ptr2 = src + width - 1;
uint16_t *dst_ptr1 = src - extend_left;
uint16_t *dst_ptr2 = src + width;
for (i = 0; i < height; ++i) {
vpx_memset16(dst_ptr1, src_ptr1[0], extend_left);
vpx_memset16(dst_ptr2, src_ptr2[0], extend_right);
src_ptr1 += src_stride;
src_ptr2 += src_stride;
dst_ptr1 += src_stride;
dst_ptr2 += src_stride;
}
/* Now copy the top and bottom lines into each line of the respective
* borders
*/
src_ptr1 = src - extend_left;
src_ptr2 = src + src_stride * (height - 1) - extend_left;
dst_ptr1 = src + src_stride * -extend_top - extend_left;
dst_ptr2 = src + src_stride * height - extend_left;
for (i = 0; i < extend_top; ++i) {
vpx_memcpy(dst_ptr1, src_ptr1, linesize * sizeof(uint16_t));
dst_ptr1 += src_stride;
}
for (i = 0; i < extend_bottom; ++i) {
vpx_memcpy(dst_ptr2, src_ptr2, linesize * sizeof(uint16_t));
dst_ptr2 += src_stride;
}
}
#endif
void vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) {
const int uv_border = ybf->border / 2;
@ -64,6 +111,31 @@ void vp8_yv12_extend_frame_borders_c(YV12_BUFFER_CONFIG *ybf) {
assert(ybf->y_height - ybf->y_crop_height >= 0);
assert(ybf->y_width - ybf->y_crop_width >= 0);
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) {
extend_plane_high(
ybf->y_buffer, ybf->y_stride,
ybf->y_crop_width, ybf->y_crop_height,
ybf->border, ybf->border,
ybf->border + ybf->y_height - ybf->y_crop_height,
ybf->border + ybf->y_width - ybf->y_crop_width);
extend_plane_high(
ybf->u_buffer, ybf->uv_stride,
(ybf->y_crop_width + 1) / 2, (ybf->y_crop_height + 1) / 2,
ybf->border / 2, ybf->border / 2,
(ybf->border + ybf->y_height - ybf->y_crop_height + 1) / 2,
(ybf->border + ybf->y_width - ybf->y_crop_width + 1) / 2);
extend_plane_high(
ybf->v_buffer, ybf->uv_stride,
(ybf->y_crop_width + 1) / 2, (ybf->y_crop_height + 1) / 2,
ybf->border / 2, ybf->border / 2,
(ybf->border + ybf->y_height - ybf->y_crop_height + 1) / 2,
(ybf->border + ybf->y_width - ybf->y_crop_width + 1) / 2);
return;
}
#endif
extend_plane(ybf->y_buffer, ybf->y_stride,
ybf->y_crop_width, ybf->y_crop_height,
ybf->border, ybf->border,
@ -99,6 +171,20 @@ static void extend_frame(YV12_BUFFER_CONFIG *const ybf, int ext_size) {
assert(ybf->y_height - ybf->y_crop_height >= 0);
assert(ybf->y_width - ybf->y_crop_width >= 0);
#if CONFIG_VP9_HIGHBITDEPTH
if (ybf->flags & YV12_FLAG_HIGHBITDEPTH) {
extend_plane_high(ybf->y_buffer, ybf->y_stride,
ybf->y_crop_width, ybf->y_crop_height,
ext_size, ext_size,
ext_size + ybf->y_height - ybf->y_crop_height,
ext_size + ybf->y_width - ybf->y_crop_width);
extend_plane_high(ybf->u_buffer, ybf->uv_stride,
c_w, c_h, c_et, c_el, c_eb, c_er);
extend_plane_high(ybf->v_buffer, ybf->uv_stride,
c_w, c_h, c_et, c_el, c_eb, c_er);
return;
}
#endif
extend_plane(ybf->y_buffer, ybf->y_stride,
ybf->y_crop_width, ybf->y_crop_height,
ext_size, ext_size,
@ -121,6 +207,14 @@ void vp9_extend_frame_inner_borders_c(YV12_BUFFER_CONFIG *ybf) {
VP9INNERBORDERINPIXELS : ybf->border;
extend_frame(ybf, inner_bw);
}
#if CONFIG_VP9_HIGHBITDEPTH
void memcpy_short_addr(uint8_t *dst8, const uint8_t *src8, int num) {
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
uint16_t *src = CONVERT_TO_SHORTPTR(src8);
vpx_memcpy(dst, src, num * sizeof(uint16_t));
}
#endif // CONFIG_VP9_HIGHBITDEPTH
#endif // CONFIG_VP9
// Copies the source image into the destination image and updates the
@ -140,6 +234,40 @@ void vp8_yv12_copy_frame_c(const YV12_BUFFER_CONFIG *src_ybc,
assert(src_ybc->y_height == dst_ybc->y_height);
#endif
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) {
assert(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH);
for (row = 0; row < src_ybc->y_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->y_width);
src += src_ybc->y_stride;
dst += dst_ybc->y_stride;
}
src = src_ybc->u_buffer;
dst = dst_ybc->u_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
}
src = src_ybc->v_buffer;
dst = dst_ybc->v_buffer;
for (row = 0; row < src_ybc->uv_height; ++row) {
memcpy_short_addr(dst, src, src_ybc->uv_width);
src += src_ybc->uv_stride;
dst += dst_ybc->uv_stride;
}
vp8_yv12_extend_frame_borders_c(dst_ybc);
return;
} else {
assert(!(dst_ybc->flags & YV12_FLAG_HIGHBITDEPTH));
}
#endif
for (row = 0; row < src_ybc->y_height; ++row) {
vpx_memcpy(dst, src, src_ybc->y_width);
src += src_ybc->y_stride;
@ -173,6 +301,19 @@ void vpx_yv12_copy_y_c(const YV12_BUFFER_CONFIG *src_ybc,
const uint8_t *src = src_ybc->y_buffer;
uint8_t *dst = dst_ybc->y_buffer;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (src_ybc->flags & YV12_FLAG_HIGHBITDEPTH) {
const uint16_t *src16 = CONVERT_TO_SHORTPTR(src);
uint16_t *dst16 = CONVERT_TO_SHORTPTR(dst);
for (row = 0; row < src_ybc->y_height; ++row) {
vpx_memcpy(dst16, src16, src_ybc->y_width * sizeof(uint16_t));
src16 += src_ybc->y_stride;
dst16 += dst_ybc->y_stride;
}
return;
}
#endif
for (row = 0; row < src_ybc->y_height; ++row) {
vpx_memcpy(dst, src, src_ybc->y_width);
src += src_ybc->y_stride;

Просмотреть файл

@ -55,6 +55,8 @@ typedef struct yv12_buffer_config {
int flags;
} YV12_BUFFER_CONFIG;
#define YV12_FLAG_HIGHBITDEPTH 1
int vp8_yv12_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int border);
int vp8_yv12_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
@ -63,6 +65,9 @@ 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,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border);
// Updates the yv12 buffer config with the frame buffer. If cb is not
@ -73,6 +78,9 @@ int vp9_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
// on failure.
int vp9_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf,
int width, int height, int ss_x, int ss_y,
#if CONFIG_VP9_HIGHBITDEPTH
int use_highbitdepth,
#endif
int border,
vpx_codec_frame_buffer_t *fb,
vpx_get_frame_buffer_cb_fn_t cb,

251
vpxdec.c
Просмотреть файл

@ -90,12 +90,20 @@ static const arg_def_t fb_arg =
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 @@ static const arg_def_t *vp8_pp_args[] = {
#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 update_image_md5(const vpx_image_t *img, const int planes[3],
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 @@ static void write_image_file(const vpx_image_t *img, const int planes[3],
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 @@ static FILE *open_outfile(const char *name) {
}
}
#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 main_loop(int argc, const char **argv_) {
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 main_loop(int argc, const char **argv_) {
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 @@ int main_loop(int argc, const char **argv_) {
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;
@ -601,6 +815,11 @@ int main_loop(int argc, const char **argv_) {
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;
@ -905,6 +1124,33 @@ int main_loop(int argc, const char **argv_) {
#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) {
@ -1011,6 +1257,9 @@ fail:
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);

458
vpxenc.c
Просмотреть файл

@ -200,6 +200,10 @@ static const arg_def_t experimental_bitstream =
ARG_DEF(NULL, "experimental-bitstream", 0,
"Allow experimental bitstream features.");
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static const arg_def_t test16bitinternalarg = ARG_DEF(
NULL, "test-16bit-internal", 0, "Force use of 16 bit internal buffer");
#endif
static const arg_def_t *main_args[] = {
&debugmode,
@ -248,6 +252,9 @@ static const arg_def_t *global_args[] = {
#endif
&timebase, &framerate,
&error_resilient,
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
&test16bitinternalarg,
#endif
&lag_in_frames, NULL
};
@ -381,6 +388,23 @@ static const arg_def_t frame_periodic_boost = ARG_DEF(
NULL, "frame-boost", 1,
"Enable frame periodic boost (0: off (default), 1: on)");
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static const struct arg_enum_list bitdepth_enum[] = {
{"8", VPX_BITS_8},
{"10", VPX_BITS_10},
{"12", VPX_BITS_12},
{NULL, 0}
};
static const arg_def_t bitdeptharg = ARG_DEF_ENUM("b", "bit-depth", 1,
"Bit depth for codec "
"(8 for version <=1, "
"10 or 12 for version 2)",
bitdepth_enum);
static const arg_def_t inbitdeptharg = ARG_DEF(NULL, "input-bit-depth", 1,
"Bit depth of input");
#endif
static const struct arg_enum_list tune_content_enum[] = {
{"default", VP9E_CONTENT_DEFAULT},
{"screen", VP9E_CONTENT_SCREEN},
@ -395,6 +419,9 @@ static const arg_def_t *vp9_args[] = {
&tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
&tune_ssim, &cq_level, &max_intra_rate_pct, &lossless,
&frame_parallel_decoding, &aq_mode, &frame_periodic_boost, &tune_content,
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
&bitdeptharg, &inbitdeptharg,
#endif
NULL
};
static const int vp9_arg_ctrl_map[] = {
@ -450,6 +477,102 @@ void usage_exit() {
}
#define mmin(a, b) ((a) < (b) ? (a) : (b))
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static void find_mismatch_high(const vpx_image_t *const img1,
const vpx_image_t *const img2,
int yloc[4], int uloc[4], int vloc[4]) {
uint16_t *plane1, *plane2;
uint32_t stride1, stride2;
const uint32_t bsize = 64;
const uint32_t bsizey = bsize >> img1->y_chroma_shift;
const uint32_t bsizex = bsize >> img1->x_chroma_shift;
const uint32_t c_w =
(img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
const uint32_t c_h =
(img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
int match = 1;
uint32_t i, j;
yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
plane1 = (uint16_t*)img1->planes[VPX_PLANE_Y];
plane2 = (uint16_t*)img2->planes[VPX_PLANE_Y];
stride1 = img1->stride[VPX_PLANE_Y]/2;
stride2 = img2->stride[VPX_PLANE_Y]/2;
for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
for (j = 0; match && j < img1->d_w; j += bsize) {
int k, l;
const int si = mmin(i + bsize, img1->d_h) - i;
const int sj = mmin(j + bsize, img1->d_w) - j;
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(plane1 + (i + k) * stride1 + j + l) !=
*(plane2 + (i + k) * stride2 + j + l)) {
yloc[0] = i + k;
yloc[1] = j + l;
yloc[2] = *(plane1 + (i + k) * stride1 + j + l);
yloc[3] = *(plane2 + (i + k) * stride2 + j + l);
match = 0;
break;
}
}
}
}
}
uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
plane1 = (uint16_t*)img1->planes[VPX_PLANE_U];
plane2 = (uint16_t*)img2->planes[VPX_PLANE_U];
stride1 = img1->stride[VPX_PLANE_U]/2;
stride2 = img2->stride[VPX_PLANE_U]/2;
for (i = 0, match = 1; match && i < c_h; i += bsizey) {
for (j = 0; match && j < c_w; j += bsizex) {
int k, l;
const int si = mmin(i + bsizey, c_h - i);
const int sj = mmin(j + bsizex, c_w - j);
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(plane1 + (i + k) * stride1 + j + l) !=
*(plane2 + (i + k) * stride2 + j + l)) {
uloc[0] = i + k;
uloc[1] = j + l;
uloc[2] = *(plane1 + (i + k) * stride1 + j + l);
uloc[3] = *(plane2 + (i + k) * stride2 + j + l);
match = 0;
break;
}
}
}
}
}
vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
plane1 = (uint16_t*)img1->planes[VPX_PLANE_V];
plane2 = (uint16_t*)img2->planes[VPX_PLANE_V];
stride1 = img1->stride[VPX_PLANE_V]/2;
stride2 = img2->stride[VPX_PLANE_V]/2;
for (i = 0, match = 1; match && i < c_h; i += bsizey) {
for (j = 0; match && j < c_w; j += bsizex) {
int k, l;
const int si = mmin(i + bsizey, c_h - i);
const int sj = mmin(j + bsizex, c_w - j);
for (k = 0; match && k < si; ++k) {
for (l = 0; match && l < sj; ++l) {
if (*(plane1 + (i + k) * stride1 + j + l) !=
*(plane2 + (i + k) * stride2 + j + l)) {
vloc[0] = i + k;
vloc[1] = j + l;
vloc[2] = *(plane1 + (i + k) * stride1 + j + l);
vloc[3] = *(plane2 + (i + k) * stride2 + j + l);
match = 0;
break;
}
}
}
}
}
}
#endif
static void find_mismatch(const vpx_image_t *const img1,
const vpx_image_t *const img2,
int yloc[4], int uloc[4], int vloc[4]) {
@ -542,7 +665,8 @@ static void find_mismatch(const vpx_image_t *const img1,
static int compare_img(const vpx_image_t *const img1,
const vpx_image_t *const img2) {
const uint32_t c_w =
uint32_t l_w = img1->d_w;
uint32_t c_w =
(img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
const uint32_t c_h =
(img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
@ -552,11 +676,17 @@ static int compare_img(const vpx_image_t *const img1,
match &= (img1->fmt == img2->fmt);
match &= (img1->d_w == img2->d_w);
match &= (img1->d_h == img2->d_h);
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (img1->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
l_w *= 2;
c_w *= 2;
}
#endif
for (i = 0; i < img1->d_h; ++i)
match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
img1->d_w) == 0);
l_w) == 0);
for (i = 0; i < c_h; ++i)
match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
@ -601,6 +731,10 @@ struct stream_config {
int arg_ctrl_cnt;
int write_webm;
int have_kf_max_dist;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
// whether to use 16bit internal buffers
int use_16bit_internal;
#endif
};
@ -873,6 +1007,9 @@ static int parse_stream_params(struct VpxEncoderConfig *global,
static const int *ctrl_args_map = NULL;
struct stream_config *config = &stream->config;
int eos_mark_found = 0;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
int test_16bit_internal = 0;
#endif
// Handle codec specific options
if (0) {
@ -921,6 +1058,12 @@ static int parse_stream_params(struct VpxEncoderConfig *global,
config->cfg.g_w = arg_parse_uint(&arg);
} else if (arg_match(&arg, &height, argi)) {
config->cfg.g_h = arg_parse_uint(&arg);
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
} else if (arg_match(&arg, &bitdeptharg, argi)) {
config->cfg.g_bit_depth = arg_parse_enum_or_int(&arg);
} else if (arg_match(&arg, &inbitdeptharg, argi)) {
config->cfg.g_input_bit_depth = arg_parse_uint(&arg);
#endif
#if CONFIG_WEBM_IO
} else if (arg_match(&arg, &stereo_mode, argi)) {
config->stereo_fmt = arg_parse_enum_or_int(&arg);
@ -988,6 +1131,12 @@ static int parse_stream_params(struct VpxEncoderConfig *global,
config->have_kf_max_dist = 1;
} else if (arg_match(&arg, &kf_disabled, argi)) {
config->cfg.kf_mode = VPX_KF_DISABLED;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
} else if (arg_match(&arg, &test16bitinternalarg, argi)) {
if (strcmp(global->codec->name, "vp9") == 0) {
test_16bit_internal = 1;
}
#endif
} else {
int i, match = 0;
for (i = 0; ctrl_args[i]; i++) {
@ -1018,6 +1167,12 @@ static int parse_stream_params(struct VpxEncoderConfig *global,
argj++;
}
}
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (strcmp(global->codec->name, "vp9") == 0) {
config->use_16bit_internal = test_16bit_internal |
(config->cfg.g_profile > 1);
}
#endif
return eos_mark_found;
}
@ -1045,6 +1200,14 @@ static void validate_stream_config(const struct stream_state *stream,
experimental_bitstream.long_name);
}
// Check that the codec bit depth is greater than the input bit depth.
if (stream->config.cfg.g_input_bit_depth >
(int)stream->config.cfg.g_bit_depth) {
fatal("Stream %d: codec bit depth (%d) less than input bit depth (%d)",
stream->index, (int)stream->config.cfg.g_bit_depth,
stream->config.cfg.g_input_bit_depth);
}
for (streami = stream; streami; streami = streami->next) {
/* All streams require output files */
if (!streami->config.out_fn)
@ -1153,6 +1316,8 @@ static void show_stream_config(struct stream_state *stream,
SHOW(g_profile);
SHOW(g_w);
SHOW(g_h);
SHOW(g_bit_depth);
SHOW(g_input_bit_depth);
SHOW(g_timebase.num);
SHOW(g_timebase.den);
SHOW(g_error_resilient);
@ -1285,6 +1450,9 @@ static void initialize_encoder(struct stream_state *stream,
flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0;
flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
flags |= stream->config.use_16bit_internal ? VPX_CODEC_USE_HIGHBITDEPTH : 0;
#endif
/* Construct Encoder Context */
vpx_codec_enc_init(&stream->encoder, global->codec->codec_interface(),
@ -1330,6 +1498,46 @@ static void encode_frame(struct stream_state *stream,
/ cfg->g_timebase.num / global->framerate.num;
/* Scale if necessary */
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (img) {
if ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) &&
(img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
if (img->fmt != VPX_IMG_FMT_I42016) {
fprintf(stderr, "%s can only scale 4:2:0 inputs\n", exec_name);
exit(EXIT_FAILURE);
}
#if CONFIG_LIBYUV
if (!stream->img) {
stream->img = vpx_img_alloc(NULL, VPX_IMG_FMT_I42016,
cfg->g_w, cfg->g_h, 16);
}
I420Scale_16((uint16*)img->planes[VPX_PLANE_Y],
img->stride[VPX_PLANE_Y]/2,
(uint16*)img->planes[VPX_PLANE_U],
img->stride[VPX_PLANE_U]/2,
(uint16*)img->planes[VPX_PLANE_V],
img->stride[VPX_PLANE_V]/2,
img->d_w, img->d_h,
(uint16*)stream->img->planes[VPX_PLANE_Y],
stream->img->stride[VPX_PLANE_Y]/2,
(uint16*)stream->img->planes[VPX_PLANE_U],
stream->img->stride[VPX_PLANE_U]/2,
(uint16*)stream->img->planes[VPX_PLANE_V],
stream->img->stride[VPX_PLANE_V]/2,
stream->img->d_w, stream->img->d_h,
kFilterBox);
img = stream->img;
#else
stream->encoder.err = 1;
ctx_exit_on_error(&stream->encoder,
"Stream %d: Failed to encode frame.\n"
"Scaling disabled in this configuration. \n"
"To enable, configure with --enable-libyuv\n",
stream->index);
#endif
}
}
#endif
if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
if (img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_YV12) {
fprintf(stderr, "%s can only scale 4:2:0 8bpp inputs\n", exec_name);
@ -1508,6 +1716,131 @@ static float usec_to_fps(uint64_t usec, unsigned int frames) {
return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0);
}
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
static void high_img_upshift(vpx_image_t *dst, vpx_image_t *src,
int input_shift) {
// Note the offset is 1 less than half
const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
int plane;
if (dst->w != src->w || dst->h != src->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->w;
int h = src->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) {
// Note the offset is 1 less than half
const int offset = input_shift > 0 ? (1 << (input_shift - 1)) - 1 : 0;
int plane;
if (dst->w != src->w || dst->h != src->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->w;
int h = src->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 img_cast_16_to_8(vpx_image_t *dst, vpx_image_t *src) {
int plane;
if (dst->fmt + VPX_IMG_FMT_HIGHBITDEPTH != src->fmt ||
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) {
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++;
}
}
}
}
#endif
static void test_decode(struct stream_state *stream,
enum TestDecodeFatality fatal,
@ -1534,20 +1867,44 @@ static void test_decode(struct stream_state *stream,
vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc);
vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec);
} else {
struct vp9_ref_frame ref;
struct vp9_ref_frame ref_enc, ref_dec;
ref.idx = 0;
vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref);
enc_img = ref.img;
vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref);
dec_img = ref.img;
ref_enc.idx = 0;
ref_dec.idx = 0;
vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref_enc);
enc_img = ref_enc.img;
vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref_dec);
dec_img = ref_dec.img;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if ((enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) !=
(dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH)) {
if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
vpx_img_alloc(&enc_img, enc_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH,
enc_img.d_w, enc_img.d_h, 16);
img_cast_16_to_8(&enc_img, &ref_enc.img);
}
if (dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
vpx_img_alloc(&dec_img, dec_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH,
dec_img.d_w, dec_img.d_h, 16);
img_cast_16_to_8(&dec_img, &ref_dec.img);
}
}
#endif
}
ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame");
ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame");
if (!compare_img(&enc_img, &dec_img)) {
int y[4], u[4], v[4];
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
find_mismatch_high(&enc_img, &dec_img, y, u, v);
} else {
find_mismatch(&enc_img, &dec_img, y, u, v);
}
#else
find_mismatch(&enc_img, &dec_img, y, u, v);
#endif
stream->decoder.err = 1;
warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL,
"Stream %d: Encode/decode mismatch on frame %d at"
@ -1589,6 +1946,12 @@ static void print_time(const char *label, int64_t etl) {
int main(int argc, const char **argv_) {
int pass;
vpx_image_t raw;
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
vpx_image_t raw_shift;
int allocated_raw_shift = 0;
int use_16bit_internal = 0;
int input_shift = 0;
#endif
int frame_avail, got_data;
struct VpxInputContext input;
@ -1690,6 +2053,27 @@ int main(int argc, const char **argv_) {
if (!input.width || !input.height)
fatal("Specify stream dimensions with --width (-w) "
" and --height (-h)");
/* If input file does not specify bit-depth but input-bit-depth parameter
* exists, assume that to be the input bit-depth. However, if the
* input-bit-depth paramter does not exist, assume the input bit-depth
* to be the same as the codec bit-depth.
*/
if (!input.bit_depth) {
FOREACH_STREAM({
if (stream->config.cfg.g_input_bit_depth)
input.bit_depth = stream->config.cfg.g_input_bit_depth;
else
input.bit_depth = stream->config.cfg.g_input_bit_depth =
(int)stream->config.cfg.g_bit_depth;
});
if (input.bit_depth > 8) input.fmt |= VPX_IMG_FMT_HIGHBITDEPTH;
} else {
FOREACH_STREAM({
stream->config.cfg.g_input_bit_depth = input.bit_depth;
});
}
FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height));
FOREACH_STREAM(validate_stream_config(stream, &global));
@ -1743,6 +2127,25 @@ int main(int argc, const char **argv_) {
FOREACH_STREAM(open_output_file(stream, &global));
FOREACH_STREAM(initialize_encoder(stream, &global));
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (strcmp(global.codec->name, "vp9") == 0) {
// Check to see if at least one stream uses 16 bit internal.
// Currently assume that the bit_depths for all streams using
// highbitdepth are the same.
FOREACH_STREAM({
if (stream->config.use_16bit_internal) {
use_16bit_internal = 1;
}
if (stream->config.cfg.g_profile == 0) {
input_shift = 0;
} else {
input_shift = (int)stream->config.cfg.g_bit_depth -
stream->config.cfg.g_input_bit_depth;
}
});
}
#endif
frame_avail = 1;
got_data = 0;
@ -1780,10 +2183,45 @@ int main(int argc, const char **argv_) {
frame_avail = 0;
if (frames_in > global.skip_frames) {
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
vpx_image_t *frame_to_encode;
if (input_shift || (use_16bit_internal && input.bit_depth == 8)) {
assert(use_16bit_internal);
// Input bit depth and stream bit depth do not match, so up
// shift frame to stream bit depth
if (!allocated_raw_shift) {
vpx_img_alloc(&raw_shift, raw.fmt | VPX_IMG_FMT_HIGHBITDEPTH,
input.width, input.height, 32);
allocated_raw_shift = 1;
}
img_upshift(&raw_shift, &raw, input_shift);
frame_to_encode = &raw_shift;
} else {
frame_to_encode = &raw;
}
vpx_usec_timer_start(&timer);
if (use_16bit_internal) {
assert(frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH);
FOREACH_STREAM({
if (stream->config.use_16bit_internal)
encode_frame(stream, &global,
frame_avail ? frame_to_encode : NULL,
frames_in);
else
assert(0);
});
} else {
assert((frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH) == 0);
FOREACH_STREAM(encode_frame(stream, &global,
frame_avail ? frame_to_encode : NULL,
frames_in));
}
#else
vpx_usec_timer_start(&timer);
FOREACH_STREAM(encode_frame(stream, &global,
frame_avail ? &raw : NULL,
frames_in));
#endif
vpx_usec_timer_mark(&timer);
cx_time += vpx_usec_timer_elapsed(&timer);
@ -1901,6 +2339,10 @@ int main(int argc, const char **argv_) {
});
#endif
#if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
if (allocated_raw_shift)
vpx_img_free(&raw_shift);
#endif
vpx_img_free(&raw);
free(argv);
free(streams);