Reworks high-bit-depth profiles

Splits profile 2 into Profile 2 and 3, where profile 2
ony supports 420 sampling, while profile 3 adds 422/444 and
alpha. Keeps room for further expansion.

Also makes some minor changes in the decoder parameters,
replacing --convert-to-8bit with output-bit-depth.

Change-Id: I713525880512de6c36698d212795db1543c1d0dd
This commit is contained in:
Deb Mukherjee
2014-06-10 16:43:59 -07:00
parent f08489e609
commit 093a32ffd7
7 changed files with 80 additions and 51 deletions

View File

@@ -26,14 +26,17 @@ extern "C" {
#define MI_MASK (MI_BLOCK_SIZE - 1) #define MI_MASK (MI_BLOCK_SIZE - 1)
// Bitstream profiles indicated by 2 bits in the uncompressed header. // Bitstream profiles indicated by 2 bits in the uncompressed header.
// 00: Profile 0. 4:2:0 only. // 00: Profile 0. 8-bit 4:2:0 only.
// 10: Profile 1. adds 4:4:4, 4:2:2, alpha. // 10: Profile 1. Adds 4:4:4, 4:2:2, alpha to Profile 0.
// 01: Profile 2. Supports 10-bit and 12-bit color only. // 01: Profile 2. Supports 10-bit and 12-bit color only, with 4:2:0 sampling.
// 11: Undefined profile. // 110: Profile 3. Supports 10-bit and 12-bit color only, with 4:2:2/4:4:4
// sampling and alpha.
// 111: Undefined profile.
typedef enum BITSTREAM_PROFILE { typedef enum BITSTREAM_PROFILE {
PROFILE_0, PROFILE_0,
PROFILE_1, PROFILE_1,
PROFILE_2, PROFILE_2,
PROFILE_3,
MAX_PROFILES MAX_PROFILES
} BITSTREAM_PROFILE; } BITSTREAM_PROFILE;

View File

@@ -1109,9 +1109,11 @@ static void error_handler(void *data) {
vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet"); vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet");
} }
static BITSTREAM_PROFILE read_profile(struct vp9_read_bit_buffer *rb) { BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb) {
int profile = vp9_rb_read_bit(rb); int profile = vp9_rb_read_bit(rb);
profile |= vp9_rb_read_bit(rb) << 1; profile |= vp9_rb_read_bit(rb) << 1;
if (profile > 2)
profile += vp9_rb_read_bit(rb);
return (BITSTREAM_PROFILE) profile; return (BITSTREAM_PROFILE) profile;
} }
@@ -1127,7 +1129,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
"Invalid frame marker"); "Invalid frame marker");
cm->profile = read_profile(rb); cm->profile = vp9_read_profile(rb);
if (cm->profile >= MAX_PROFILES) if (cm->profile >= MAX_PROFILES)
vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM,
"Unsupported bitstream profile"); "Unsupported bitstream profile");
@@ -1173,7 +1175,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3); cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3);
if (cm->color_space != SRGB) { if (cm->color_space != SRGB) {
vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range vp9_rb_read_bit(rb); // [16,235] (including xvycc) vs [0,255] range
if (cm->profile >= PROFILE_1) { if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
cm->subsampling_x = vp9_rb_read_bit(rb); cm->subsampling_x = vp9_rb_read_bit(rb);
cm->subsampling_y = vp9_rb_read_bit(rb); cm->subsampling_y = vp9_rb_read_bit(rb);
vp9_rb_read_bit(rb); // has extra plane vp9_rb_read_bit(rb); // has extra plane
@@ -1181,7 +1183,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi,
cm->subsampling_y = cm->subsampling_x = 1; cm->subsampling_y = cm->subsampling_x = 1;
} }
} else { } else {
if (cm->profile >= PROFILE_1) { if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
cm->subsampling_y = cm->subsampling_x = 0; cm->subsampling_y = cm->subsampling_x = 0;
vp9_rb_read_bit(rb); // has extra plane vp9_rb_read_bit(rb); // has extra plane
} else { } else {

View File

@@ -18,6 +18,7 @@ extern "C" {
struct VP9Common; struct VP9Common;
struct VP9Decoder; struct VP9Decoder;
struct vp9_read_bit_buffer;
void vp9_init_dequantizer(struct VP9Common *cm); void vp9_init_dequantizer(struct VP9Common *cm);
@@ -25,6 +26,8 @@ void vp9_decode_frame(struct VP9Decoder *pbi,
const uint8_t *data, const uint8_t *data_end, const uint8_t *data, const uint8_t *data_end,
const uint8_t **p_data_end); const uint8_t **p_data_end);
BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb);
#ifdef __cplusplus #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@@ -1036,8 +1036,27 @@ static void write_sync_code(struct vp9_write_bit_buffer *wb) {
static void write_profile(BITSTREAM_PROFILE profile, static void write_profile(BITSTREAM_PROFILE profile,
struct vp9_write_bit_buffer *wb) { struct vp9_write_bit_buffer *wb) {
assert(profile < MAX_PROFILES); assert(profile < MAX_PROFILES);
vp9_wb_write_bit(wb, profile & 1); switch (profile) {
vp9_wb_write_bit(wb, profile >> 1); case PROFILE_0:
vp9_wb_write_bit(wb, 0);
vp9_wb_write_bit(wb, 0);
break;
case PROFILE_1:
vp9_wb_write_bit(wb, 1);
vp9_wb_write_bit(wb, 0);
break;
case PROFILE_2:
vp9_wb_write_bit(wb, 0);
vp9_wb_write_bit(wb, 1);
break;
case PROFILE_3:
vp9_wb_write_bit(wb, 1);
vp9_wb_write_bit(wb, 1);
vp9_wb_write_bit(wb, 0);
break;
default:
assert(0);
}
} }
static void write_uncompressed_header(VP9_COMP *cpi, static void write_uncompressed_header(VP9_COMP *cpi,
@@ -1063,16 +1082,15 @@ static void write_uncompressed_header(VP9_COMP *cpi,
vp9_wb_write_literal(wb, cs, 3); vp9_wb_write_literal(wb, cs, 3);
if (cs != SRGB) { if (cs != SRGB) {
vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255] vp9_wb_write_bit(wb, 0); // 0: [16, 235] (i.e. xvYCC), 1: [0, 255]
if (cm->profile >= PROFILE_1) { if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) {
vp9_wb_write_bit(wb, cm->subsampling_x); vp9_wb_write_bit(wb, cm->subsampling_x);
vp9_wb_write_bit(wb, cm->subsampling_y); vp9_wb_write_bit(wb, cm->subsampling_y);
vp9_wb_write_bit(wb, 0); // has extra plane vp9_wb_write_bit(wb, 0); // has extra plane
} }
} else { } else {
assert(cm->profile == PROFILE_1); assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3);
vp9_wb_write_bit(wb, 0); // has extra plane vp9_wb_write_bit(wb, 0); // has extra plane
} }
write_frame_size(cm, wb); write_frame_size(cm, wb);
} else { } else {
if (!cm->show_frame) if (!cm->show_frame)

View File

@@ -21,6 +21,7 @@
#include "vp9/decoder/vp9_decoder.h" #include "vp9/decoder/vp9_decoder.h"
#include "vp9/decoder/vp9_read_bit_buffer.h" #include "vp9/decoder/vp9_read_bit_buffer.h"
#include "vp9/decoder/vp9_decodeframe.h"
#include "vp9/vp9_iface_common.h" #include "vp9/vp9_iface_common.h"
@@ -112,12 +113,11 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
{ {
struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL }; struct vp9_read_bit_buffer rb = { data, data + data_sz, 0, NULL, NULL };
const int frame_marker = vp9_rb_read_literal(&rb, 2); const int frame_marker = vp9_rb_read_literal(&rb, 2);
const int version = vp9_rb_read_bit(&rb); const BITSTREAM_PROFILE profile = vp9_read_profile(&rb);
(void) vp9_rb_read_bit(&rb); // unused version bit
if (frame_marker != VP9_FRAME_MARKER) if (frame_marker != VP9_FRAME_MARKER)
return VPX_CODEC_UNSUP_BITSTREAM; return VPX_CODEC_UNSUP_BITSTREAM;
if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM; if (profile >= MAX_PROFILES) return VPX_CODEC_UNSUP_BITSTREAM;
if (vp9_rb_read_bit(&rb)) { // show an existing frame if (vp9_rb_read_bit(&rb)) { // show an existing frame
return VPX_CODEC_OK; return VPX_CODEC_OK;
@@ -136,16 +136,17 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data,
vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) { vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) {
return VPX_CODEC_UNSUP_BITSTREAM; return VPX_CODEC_UNSUP_BITSTREAM;
} }
if (profile > PROFILE_1)
rb.bit_offset += 1; // Bit-depth 10 or 12
colorspace = vp9_rb_read_literal(&rb, 3); colorspace = vp9_rb_read_literal(&rb, 3);
if (colorspace != sRGB) { if (colorspace != sRGB) {
rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range rb.bit_offset += 1; // [16,235] (including xvycc) vs [0,255] range
if (version == 1) { if (profile == PROFILE_1 || profile == PROFILE_3) {
rb.bit_offset += 2; // subsampling x/y rb.bit_offset += 2; // subsampling x/y
rb.bit_offset += 1; // has extra plane rb.bit_offset += 1; // has extra plane
} }
} else { } else {
if (version == 1) { if (profile == PROFILE_1 || profile == PROFILE_3) {
rb.bit_offset += 1; // has extra plane rb.bit_offset += 1; // has extra plane
} else { } else {
// RGB is only available in version 1 // RGB is only available in version 1

View File

@@ -84,9 +84,9 @@ static const arg_def_t fb_arg =
static const arg_def_t md5arg = ARG_DEF( static const arg_def_t md5arg = ARG_DEF(
NULL, "md5", 0, "Compute the MD5 sum of the decoded frame"); NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
#if CONFIG_VP9_HIGH #if CONFIG_VP9_HIGH
static const arg_def_t convertto8bitarg = ARG_DEF( static const arg_def_t outbitdeptharg = ARG_DEF(
NULL, "convert-to-8bit", 0, NULL, "output-bit-depth", 1,
"Output 8-bit frames even for high bitdepth streams"); "Output bit-depth for decoded frames");
#endif #endif
static const arg_def_t *all_args[] = { static const arg_def_t *all_args[] = {
@@ -96,7 +96,7 @@ static const arg_def_t *all_args[] = {
&md5arg, &md5arg,
&error_concealment, &error_concealment,
#if CONFIG_VP9_HIGH #if CONFIG_VP9_HIGH
&convertto8bitarg, &outbitdeptharg,
#endif #endif
NULL NULL
}; };
@@ -579,7 +579,7 @@ int main_loop(int argc, const char **argv_) {
int use_y4m = 1; int use_y4m = 1;
vpx_codec_dec_cfg_t cfg = {0}; vpx_codec_dec_cfg_t cfg = {0};
#if CONFIG_VP9_HIGH #if CONFIG_VP9_HIGH
int convert_to_8bit = 0; int out_bit_depth = 0;
#endif #endif
#if CONFIG_VP8_DECODER #if CONFIG_VP8_DECODER
vp8_postproc_cfg_t vp8_pp_cfg = {0}; vp8_postproc_cfg_t vp8_pp_cfg = {0};
@@ -662,8 +662,8 @@ int main_loop(int argc, const char **argv_) {
num_external_frame_buffers = arg_parse_uint(&arg); num_external_frame_buffers = arg_parse_uint(&arg);
#if CONFIG_VP9_HIGH #if CONFIG_VP9_HIGH
else if (arg_match(&arg, &convertto8bitarg, argi)) { else if (arg_match(&arg, &outbitdeptharg, argi)) {
convert_to_8bit = 1; out_bit_depth = arg_parse_uint(&arg);
} }
#endif #endif
@@ -850,7 +850,6 @@ int main_loop(int argc, const char **argv_) {
} }
#endif #endif
if (arg_skip) if (arg_skip)
fprintf(stderr, "Skipping first %d frames.\n", arg_skip); fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
while (arg_skip) { while (arg_skip) {
@@ -980,23 +979,21 @@ int main_loop(int argc, const char **argv_) {
} }
} }
#if CONFIG_VP9_HIGH #if CONFIG_VP9_HIGH
if (convert_to_8bit) {
// Convert to an 8bit image // Convert to an 8bit image
if (img->fmt & VPX_IMG_FMT_HIGH) { if (img->fmt & VPX_IMG_FMT_HIGH) {
unsigned int bit_depth; vpx_bit_depth_t bit_depth;
unsigned int shift = 0; // BITS_8 default
if (vpx_codec_control(&decoder, VP9D_GET_BIT_DEPTH, &bit_depth)) { if (vpx_codec_control(&decoder, VP9D_GET_BIT_DEPTH, &bit_depth)) {
// Fallback to 8bit // Fallback to 8bit
bit_depth = VPX_BITS_8; bit_depth = VPX_BITS_8;
} }
switch (bit_depth) { if (out_bit_depth != 8 &&
case VPX_BITS_10: // BITS_10 out_bit_depth != bit_depth * 2 + 8) {
shift = 2; fprintf(stderr, "Does not support bit-depth conversion to: %d.\n",
break; out_bit_depth);
case VPX_BITS_12: // BITS_12 return EXIT_FAILURE;
shift = 4;
break;
} }
if (out_bit_depth == 8) {
unsigned int shift = (int)bit_depth * 2;
if (!img_8bit) { if (!img_8bit) {
img_8bit = vpx_img_alloc(NULL, img->fmt - VPX_IMG_FMT_HIGH, img_8bit = vpx_img_alloc(NULL, img->fmt - VPX_IMG_FMT_HIGH,
img->d_w, img->d_h, 16); img->d_w, img->d_h, 16);

View File

@@ -362,6 +362,13 @@ static const int vp8_arg_ctrl_map[] = {
#endif #endif
#if CONFIG_VP9_ENCODER #if CONFIG_VP9_ENCODER
static const struct arg_enum_list aq_mode_enum[] = {
{"off", 0},
{"variance", 1},
{"complexity", 2},
{"cyclic", 3},
{NULL, 0}
};
static const arg_def_t tile_cols = static const arg_def_t tile_cols =
ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2"); ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2");
static const arg_def_t tile_rows = static const arg_def_t tile_rows =
@@ -369,10 +376,8 @@ static const arg_def_t tile_rows =
static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode"); static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode");
static const arg_def_t frame_parallel_decoding = ARG_DEF( static const arg_def_t frame_parallel_decoding = ARG_DEF(
NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
static const arg_def_t aq_mode = ARG_DEF( static const arg_def_t aq_mode = ARG_DEF_ENUM(
NULL, "aq-mode", 1, NULL, "aq-mode", 1, "Adaptive quantization mode", aq_mode_enum);
"Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
"3: cyclic refresh)");
static const arg_def_t frame_periodic_boost = ARG_DEF( static const arg_def_t frame_periodic_boost = ARG_DEF(
NULL, "frame_boost", 1, NULL, "frame_boost", 1,
"Enable frame periodic boost (0: off (default), 1: on)"); "Enable frame periodic boost (0: off (default), 1: on)");
@@ -385,12 +390,12 @@ static const struct arg_enum_list bitdepth_enum[] = {
{NULL, 0} {NULL, 0}
}; };
static const arg_def_t bitdeptharg = ARG_DEF_ENUM(NULL, "bit-depth", 1, static const arg_def_t bitdeptharg = ARG_DEF_ENUM("b", "bit-depth", 1,
"Bit depth for codec " "Bit depth for codec "
"(8 for version <=1, " "(8 for version <=1, "
"10 or 12 for version 2)", "10 or 12 for version 2)",
bitdepth_enum); bitdepth_enum);
static const arg_def_t inbitdeptharg = ARG_DEF("b", "input-bit-depth", 1, static const arg_def_t inbitdeptharg = ARG_DEF(NULL, "input-bit-depth", 1,
"Bit depth of input"); "Bit depth of input");
#endif #endif
@@ -1161,7 +1166,7 @@ static void validate_stream_config(const struct stream_state *stream,
experimental_bitstream.long_name); experimental_bitstream.long_name);
} }
// Check that the stream bit depth is greater than the input bit depth // Check that the codec bit depth is greater than the input bit depth
if (stream->config.cfg.g_in_bit_depth > if (stream->config.cfg.g_in_bit_depth >
stream->config.cfg.g_bit_depth * 2 + 8) { stream->config.cfg.g_bit_depth * 2 + 8) {
fatal("Stream %d: input bit depth (%d) less than stream bit depth (%d)", fatal("Stream %d: input bit depth (%d) less than stream bit depth (%d)",