From 7c43fb67ae5f8cd3ca39756281f63cc9e29bdb55 Mon Sep 17 00:00:00 2001 From: Adrian Grange Date: Mon, 9 Jun 2014 15:22:17 -0700 Subject: [PATCH] Fix decoder handling of intra-only frames This patch fixes bug 633: https://code.google.com/p/webm/issues/detail?id=633 The first decoded frame does not have to be a keyframe, it could be an inter-frame that is coded intra-only. This patch fixes the handling of intra-only frames. A test vector has also been added that encodes 3 intra-only frames at the start of the clip. The test vector was generated using the code in the following patch: https://gerrit.chromium.org/gerrit/#/c/70680/ Change-Id: Ib40b1dbf91aae2bc047e23c626eaef09d1860147 --- test/test-data.sha1 | 2 ++ test/test.mk | 2 ++ test/test_vectors.cc | 1 + vp9/common/vp9_onyxc_int.h | 12 ++++++------ vp9/decoder/vp9_decodeframe.c | 40 ++++++++++++++++++++++++---------------- vp9/decoder/vp9_decodeframe.h | 5 +++++ vp9/decoder/vp9_decoder.c | 17 +++++++++++++---- vp9/decoder/vp9_decoder.h | 1 - vp9/vp9_dx_iface.c | 42 +++++++++++++++++++++++++++--------------- 9 files changed, 80 insertions(+), 42 deletions(-) diff --git a/test/test-data.sha1 b/test/test-data.sha1 index f9c09c6..8940027 100644 --- a/test/test-data.sha1 +++ b/test/test-data.sha1 @@ -653,6 +653,8 @@ e615575ded499ea1d992f3b38e3baa434509cdcd vp90-2-15-segkey.webm e3ab35d4316c5e81325c50f5236ceca4bc0d35df vp90-2-15-segkey.webm.md5 9b7ca2cac09d34c4a5d296c1900f93b1e2f69d0d vp90-2-15-segkey_adpq.webm 8f46ba5f785d0c2170591a153e0d0d146a7c8090 vp90-2-15-segkey_adpq.webm.md5 +698a6910a97486b833073ef0c0b18d75dce57ee8 vp90-2-16-intra-only.webm +5661b0168752969f055eec37b05fa9fa947dc7eb vp90-2-16-intra-only.webm.md5 0321d507ce62dedc8a51b4e9011f7a19aed9c3dc vp91-2-04-yuv444.webm 367e423dd41fdb49aa028574a2cfec5c2f325c5c vp91-2-04-yuv444.webm.md5 76024eb753cdac6a5e5703aaea189d35c3c30ac7 invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.ivf diff --git a/test/test.mk b/test/test.mk index 85212d9..ef81ab1 100644 --- a/test/test.mk +++ b/test/test.mk @@ -771,6 +771,8 @@ LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-15-segkey.webm LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-15-segkey.webm.md5 LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-15-segkey_adpq.webm LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-15-segkey_adpq.webm.md5 +LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-16-intra-only.webm +LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp90-2-16-intra-only.webm.md5 LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp91-2-04-yuv444.webm LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += vp91-2-04-yuv444.webm.md5 diff --git a/test/test_vectors.cc b/test/test_vectors.cc index 41c9e26..4955887 100644 --- a/test/test_vectors.cc +++ b/test/test_vectors.cc @@ -180,6 +180,7 @@ const char *const kVP9TestVectors[] = { "vp90-2-14-resize-fp-tiles-8-16.webm", "vp90-2-14-resize-fp-tiles-8-1.webm", "vp90-2-14-resize-fp-tiles-8-2.webm", "vp90-2-14-resize-fp-tiles-8-4.webm", "vp90-2-15-segkey.webm", "vp90-2-15-segkey_adpq.webm", + "vp90-2-16-intra-only.webm", "vp91-2-04-yuv444.webm", }; const int kNumVP9TestVectors = NELEMENTS(kVP9TestVectors); diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index e1753a1..afe831a 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -257,10 +257,14 @@ static INLINE void init_macroblockd(VP9_COMMON *cm, MACROBLOCKD *xd) { xd->mi_stride = cm->mi_stride; } +static INLINE int frame_is_intra_only(const VP9_COMMON *const cm) { + return cm->frame_type == KEY_FRAME || cm->intra_only; +} + static INLINE const vp9_prob* get_partition_probs(const VP9_COMMON *cm, int ctx) { - return cm->frame_type == KEY_FRAME ? vp9_kf_partition_probs[ctx] - : cm->fc.partition_prob[ctx]; + return frame_is_intra_only(cm) ? vp9_kf_partition_probs[ctx] + : cm->fc.partition_prob[ctx]; } static INLINE void set_skip_context(MACROBLOCKD *xd, int mi_row, int mi_col) { @@ -299,10 +303,6 @@ static INLINE void set_prev_mi(VP9_COMMON *cm) { cm->prev_mip + cm->mi_stride + 1 : NULL; } -static INLINE int frame_is_intra_only(const VP9_COMMON *const cm) { - return cm->frame_type == KEY_FRAME || cm->intra_only; -} - static INLINE void update_partition_context(MACROBLOCKD *xd, int mi_row, int mi_col, BLOCK_SIZE subsize, diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 8b96abb..6fc1303 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -605,8 +605,8 @@ static INTERP_FILTER read_interp_filter(struct vp9_read_bit_buffer *rb) { : literal_to_filter[vp9_rb_read_literal(rb, 2)]; } -static void read_frame_size(struct vp9_read_bit_buffer *rb, - int *width, int *height) { +void vp9_read_frame_size(struct vp9_read_bit_buffer *rb, + int *width, int *height) { const int w = vp9_rb_read_literal(rb, 16) + 1; const int h = vp9_rb_read_literal(rb, 16) + 1; *width = w; @@ -617,7 +617,7 @@ static void setup_display_size(VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) { cm->display_width = cm->width; cm->display_height = cm->height; if (vp9_rb_read_bit(rb)) - read_frame_size(rb, &cm->display_width, &cm->display_height); + vp9_read_frame_size(rb, &cm->display_width, &cm->display_height); } static void apply_frame_size(VP9_COMMON *cm, int width, int height) { @@ -649,7 +649,7 @@ static void apply_frame_size(VP9_COMMON *cm, int width, int height) { static void setup_frame_size(VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) { int width, height; - read_frame_size(rb, &width, &height); + vp9_read_frame_size(rb, &width, &height); apply_frame_size(cm, width, height); setup_display_size(cm, rb); } @@ -669,7 +669,7 @@ static void setup_frame_size_with_refs(VP9_COMMON *cm, } if (!found) - read_frame_size(rb, &width, &height); + vp9_read_frame_size(rb, &width, &height); // Check that each of the frames that this frame references has valid // dimensions. @@ -1053,20 +1053,17 @@ static const uint8_t *decode_tiles_mt(VP9Decoder *pbi, return bit_reader_end; } -static void check_sync_code(VP9_COMMON *cm, struct vp9_read_bit_buffer *rb) { - if (vp9_rb_read_literal(rb, 8) != VP9_SYNC_CODE_0 || - vp9_rb_read_literal(rb, 8) != VP9_SYNC_CODE_1 || - vp9_rb_read_literal(rb, 8) != VP9_SYNC_CODE_2) { - vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, - "Invalid frame sync code"); - } -} - static void error_handler(void *data) { VP9_COMMON *const cm = (VP9_COMMON *)data; vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME, "Truncated packet"); } +int vp9_read_sync_code(struct vp9_read_bit_buffer *const rb) { + return vp9_rb_read_literal(rb, 8) == VP9_SYNC_CODE_0 && + vp9_rb_read_literal(rb, 8) == VP9_SYNC_CODE_1 && + vp9_rb_read_literal(rb, 8) == VP9_SYNC_CODE_2; +} + static BITSTREAM_PROFILE read_profile(struct vp9_read_bit_buffer *rb) { int profile = vp9_rb_read_bit(rb); profile |= vp9_rb_read_bit(rb) << 1; @@ -1112,7 +1109,9 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, cm->error_resilient_mode = vp9_rb_read_bit(rb); if (cm->frame_type == KEY_FRAME) { - check_sync_code(cm, rb); + if (!vp9_read_sync_code(rb)) + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "Invalid frame sync code"); if (cm->profile > PROFILE_1) cm->bit_depth = vp9_rb_read_bit(rb) ? BITS_12 : BITS_10; cm->color_space = (COLOR_SPACE)vp9_rb_read_literal(rb, 3); @@ -1150,9 +1149,18 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, 0 : vp9_rb_read_literal(rb, 2); if (cm->intra_only) { - check_sync_code(cm, rb); + if (!vp9_read_sync_code(rb)) + vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, + "Invalid frame sync code"); pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); + + // NOTE: The intra-only frame header does not include the specification of + // either the color format or color sub-sampling. VP9 specifies that the + // default color space should be YUV 4:2:0 in this case (normative). + cm->color_space = BT_601; + cm->subsampling_y = cm->subsampling_x = 1; + setup_frame_size(cm, rb); } else { pbi->refresh_frame_flags = vp9_rb_read_literal(rb, REF_FRAMES); diff --git a/vp9/decoder/vp9_decodeframe.h b/vp9/decoder/vp9_decodeframe.h index fb15645..e5d9d62 100644 --- a/vp9/decoder/vp9_decodeframe.h +++ b/vp9/decoder/vp9_decodeframe.h @@ -18,6 +18,7 @@ extern "C" { struct VP9Common; struct VP9Decoder; +struct vp9_read_bit_buffer; void vp9_init_dequantizer(struct VP9Common *cm); @@ -25,6 +26,10 @@ void vp9_decode_frame(struct VP9Decoder *pbi, const uint8_t *data, const uint8_t *data_end, const uint8_t **p_data_end); +int vp9_read_sync_code(struct vp9_read_bit_buffer *const rb); +void vp9_read_frame_size(struct vp9_read_bit_buffer *rb, + int *width, int *height); + #ifdef __cplusplus } // extern "C" #endif diff --git a/vp9/decoder/vp9_decoder.c b/vp9/decoder/vp9_decoder.c index d154e9d..6f1f21f 100644 --- a/vp9/decoder/vp9_decoder.c +++ b/vp9/decoder/vp9_decoder.c @@ -267,7 +267,10 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, vp9_decode_frame(pbi, source, source + size, psource); - swap_frame_buffers(pbi); + if (!cm->show_existing_frame) + swap_frame_buffers(pbi); + else + cm->frame_to_show = get_frame_new_buffer(cm); vp9_clear_system_state(); @@ -291,6 +294,7 @@ int vp9_receive_compressed_data(VP9Decoder *pbi, int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd, vp9_ppflags_t *flags) { + VP9_COMMON *const cm = &pbi->common; int ret = -1; #if !CONFIG_VP9_POSTPROC (void)*flags; @@ -300,15 +304,20 @@ int vp9_get_raw_frame(VP9Decoder *pbi, YV12_BUFFER_CONFIG *sd, return ret; /* no raw frame to show!!! */ - if (pbi->common.show_frame == 0) + if (!cm->show_frame) return ret; pbi->ready_for_new_data = 1; #if CONFIG_VP9_POSTPROC - ret = vp9_post_proc_frame(&pbi->common, sd, flags); + if (!cm->show_existing_frame) { + ret = vp9_post_proc_frame(cm, sd, flags); + } else { + *sd = *cm->frame_to_show; + ret = 0; + } #else - *sd = *pbi->common.frame_to_show; + *sd = *cm->frame_to_show; ret = 0; #endif /*!CONFIG_POSTPROC*/ vp9_clear_system_state(); diff --git a/vp9/decoder/vp9_decoder.h b/vp9/decoder/vp9_decoder.h index ab4f9a2..2a618f9 100644 --- a/vp9/decoder/vp9_decoder.h +++ b/vp9/decoder/vp9_decoder.h @@ -19,7 +19,6 @@ #include "vp9/common/vp9_onyxc_int.h" #include "vp9/common/vp9_ppflags.h" -#include "vp9/decoder/vp9_decoder.h" #include "vp9/decoder/vp9_dthread.h" #include "vp9/decoder/vp9_thread.h" diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index c3ca7ee..2591852 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -20,6 +20,7 @@ #include "vp9/common/vp9_frame_buffers.h" #include "vp9/decoder/vp9_decoder.h" +#include "vp9/decoder/vp9_decodeframe.h" #include "vp9/decoder/vp9_read_bit_buffer.h" #include "vp9/vp9_iface_common.h" @@ -98,8 +99,10 @@ static vpx_codec_err_t decoder_destroy(vpx_codec_alg_priv_t *ctx) { static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si, + int *is_intra_only, vpx_decrypt_cb decrypt_cb, void *decrypt_state) { + int intra_only_flag = 0; uint8_t clear_buffer[9]; if (data + data_sz <= data) @@ -115,6 +118,8 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, } { + int show_frame; + int error_resilient; 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 version = vp9_rb_read_bit(&rb); @@ -126,6 +131,7 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, if (version > 1) return VPX_CODEC_UNSUP_BITSTREAM; if (vp9_rb_read_bit(&rb)) { // show an existing frame + vp9_rb_read_literal(&rb, 3); // Frame buffer to show. return VPX_CODEC_OK; } @@ -133,18 +139,15 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, return VPX_CODEC_UNSUP_BITSTREAM; si->is_kf = !vp9_rb_read_bit(&rb); + show_frame = vp9_rb_read_bit(&rb); + error_resilient = vp9_rb_read_bit(&rb); + if (si->is_kf) { const int sRGB = 7; int colorspace; - rb.bit_offset += 1; // show frame - rb.bit_offset += 1; // error resilient - - if (vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_0 || - vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_1 || - vp9_rb_read_literal(&rb, 8) != VP9_SYNC_CODE_2) { + if (!vp9_read_sync_code(&rb)) return VPX_CODEC_UNSUP_BITSTREAM; - } colorspace = vp9_rb_read_literal(&rb, 3); if (colorspace != sRGB) { @@ -161,20 +164,28 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, return VPX_CODEC_UNSUP_BITSTREAM; } } + vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); + } else { + intra_only_flag = show_frame ? 0 : vp9_rb_read_bit(&rb); + rb.bit_offset += error_resilient ? 0 : 2; // reset_frame_context - // TODO(jzern): these are available on non-keyframes in intra only mode. - si->w = vp9_rb_read_literal(&rb, 16) + 1; - si->h = vp9_rb_read_literal(&rb, 16) + 1; + if (intra_only_flag) { + if (!vp9_read_sync_code(&rb)) + return VPX_CODEC_UNSUP_BITSTREAM; + rb.bit_offset += REF_FRAMES; // refresh_frame_flags + vp9_read_frame_size(&rb, (int *)&si->w, (int *)&si->h); + } } } - + if (is_intra_only != NULL) + *is_intra_only = intra_only_flag; return VPX_CODEC_OK; } static vpx_codec_err_t decoder_peek_si(const uint8_t *data, unsigned int data_sz, vpx_codec_stream_info_t *si) { - return decoder_peek_si_internal(data, data_sz, si, NULL, NULL); + return decoder_peek_si_internal(data, data_sz, si, NULL, NULL, NULL); } static vpx_codec_err_t decoder_get_si(vpx_codec_alg_priv_t *ctx, @@ -266,13 +277,14 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, // validate that we have a buffer that does not wrap around the top // of the heap. if (!ctx->si.h) { + int is_intra_only = 0; const vpx_codec_err_t res = - decoder_peek_si_internal(*data, data_sz, &ctx->si, ctx->decrypt_cb, - ctx->decrypt_state); + decoder_peek_si_internal(*data, data_sz, &ctx->si, &is_intra_only, + ctx->decrypt_cb, ctx->decrypt_state); if (res != VPX_CODEC_OK) return res; - if (!ctx->si.is_kf) + if (!ctx->si.is_kf && !is_intra_only) return VPX_CODEC_ERROR; } -- 2.7.4