diff --git a/test/decode_test_driver.cc b/test/decode_test_driver.cc index a762b036e..3e4ef0ad1 100644 --- a/test/decode_test_driver.cc +++ b/test/decode_test_driver.cc @@ -39,12 +39,34 @@ vpx_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size, return res_dec; } +bool Decoder::IsVP8() const { + const char *codec_name = GetDecoderName(); + return strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0; +} + +void DecoderTest::HandlePeekResult(Decoder *const decoder, + CompressedVideoSource *video, + const vpx_codec_err_t res_peek) { + const bool is_vp8 = decoder->IsVP8(); + if (is_vp8) { + /* Vp8's implementation of PeekStream returns an error if the frame you + * pass it is not a keyframe, so we only expect VPX_CODEC_OK on the first + * frame, which must be a keyframe. */ + if (video->frame_number() == 0) + ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: " + << vpx_codec_err_to_string(res_peek); + } else { + /* The Vp9 implementation of PeekStream returns an error only if the + * data passed to it isn't a valid Vp9 chunk. */ + ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: " + << vpx_codec_err_to_string(res_peek); + } +} + void DecoderTest::RunLoop(CompressedVideoSource *video, const vpx_codec_dec_cfg_t &dec_cfg) { Decoder* const decoder = codec_->CreateDecoder(dec_cfg, 0); ASSERT_TRUE(decoder != NULL); - const char *codec_name = decoder->GetDecoderName(); - const bool is_vp8 = strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0; // Decode frames. for (video->Begin(); !::testing::Test::HasFailure() && video->cxdata(); @@ -56,19 +78,8 @@ void DecoderTest::RunLoop(CompressedVideoSource *video, const vpx_codec_err_t res_peek = decoder->PeekStream(video->cxdata(), video->frame_size(), &stream_info); - if (is_vp8) { - /* Vp8's implementation of PeekStream returns an error if the frame you - * pass it is not a keyframe, so we only expect VPX_CODEC_OK on the first - * frame, which must be a keyframe. */ - if (video->frame_number() == 0) - ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: " - << vpx_codec_err_to_string(res_peek); - } else { - /* The Vp9 implementation of PeekStream returns an error only if the - * data passed to it isn't a valid Vp9 chunk. */ - ASSERT_EQ(VPX_CODEC_OK, res_peek) << "Peek return failed: " - << vpx_codec_err_to_string(res_peek); - } + HandlePeekResult(decoder, video, res_peek); + ASSERT_FALSE(::testing::Test::HasFailure()); vpx_codec_err_t res_dec = decoder->DecodeFrame(video->cxdata(), video->frame_size()); diff --git a/test/decode_test_driver.h b/test/decode_test_driver.h index a3cfd3f52..1f73c7d20 100644 --- a/test/decode_test_driver.h +++ b/test/decode_test_driver.h @@ -91,10 +91,12 @@ class Decoder { &decoder_, cb_get, cb_release, user_priv); } - const char* GetDecoderName() { + const char* GetDecoderName() const { return vpx_codec_iface_name(CodecInterface()); } + bool IsVP8() const; + protected: virtual vpx_codec_iface_t* CodecInterface() const = 0; @@ -138,6 +140,11 @@ class DecoderTest { virtual void DecompressedFrameHook(const vpx_image_t& img, const unsigned int frame_number) {} + // Hook to be called on peek result + virtual void HandlePeekResult(Decoder* const decoder, + CompressedVideoSource *video, + const vpx_codec_err_t res_peek); + protected: explicit DecoderTest(const CodecFactory *codec) : codec_(codec) {} diff --git a/test/invalid_file_test.cc b/test/invalid_file_test.cc index 8d7114fac..9034d25ee 100644 --- a/test/invalid_file_test.cc +++ b/test/invalid_file_test.cc @@ -66,46 +66,49 @@ class InvalidFileTest return !HasFailure(); } + void RunTest() { + const DecodeParam input = GET_PARAM(1); + libvpx_test::CompressedVideoSource *video = NULL; + vpx_codec_dec_cfg_t cfg = {0}; + cfg.threads = input.threads; + const std::string filename = input.filename; + + // Open compressed video file. + if (filename.substr(filename.length() - 3, 3) == "ivf") { + video = new libvpx_test::IVFVideoSource(filename); + } else if (filename.substr(filename.length() - 4, 4) == "webm") { +#if CONFIG_WEBM_IO + video = new libvpx_test::WebMVideoSource(filename); +#else + fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n", + filename.c_str()); + return; +#endif + } + video->Init(); + + // Construct result file name. The file holds a list of expected integer + // results, one for each decoded frame. Any result that doesn't match + // the files list will cause a test failure. + const std::string res_filename = filename + ".res"; + OpenResFile(res_filename); + + // Decode frame, and check the md5 matching. + ASSERT_NO_FATAL_FAILURE(RunLoop(video, cfg)); + delete video; + } + private: FILE *res_file_; }; TEST_P(InvalidFileTest, ReturnCode) { - libvpx_test::CompressedVideoSource *video = NULL; - const DecodeParam input = GET_PARAM(1); - vpx_codec_dec_cfg_t cfg = {0}; - cfg.threads = input.threads; - const std::string filename = input.filename; - - // Open compressed video file. - if (filename.substr(filename.length() - 3, 3) == "ivf") { - video = new libvpx_test::IVFVideoSource(filename); - } else if (filename.substr(filename.length() - 4, 4) == "webm") { -#if CONFIG_WEBM_IO - video = new libvpx_test::WebMVideoSource(filename); -#else - fprintf(stderr, "WebM IO is disabled, skipping test vector %s\n", - filename.c_str()); - return; -#endif - } - video->Init(); - - // Construct result file name. The file holds a list of expected integer - // results, one for each decoded frame. Any result that doesn't match - // the files list will cause a test failure. - const std::string res_filename = filename + ".res"; - OpenResFile(res_filename); - - // Decode frame, and check the md5 matching. - ASSERT_NO_FATAL_FAILURE(RunLoop(video, cfg)); - delete video; + RunTest(); } const DecodeParam kVP9InvalidFileTests[] = { - {1, "invalid-vp90-01-v2.webm"}, {1, "invalid-vp90-02-v2.webm"}, - {1, "invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.ivf"}, + {1, "invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf"}, {1, "invalid-vp90-03-v2.webm"}, {1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf"}, {1, "invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf"}, @@ -114,6 +117,27 @@ const DecodeParam kVP9InvalidFileTests[] = { VP9_INSTANTIATE_TEST_CASE(InvalidFileTest, ::testing::ValuesIn(kVP9InvalidFileTests)); +// This class will include test vectors that are expected to fail +// peek. However they are still expected to have no fatal failures. +class InvalidFileInvalidPeekTest : public InvalidFileTest { + protected: + InvalidFileInvalidPeekTest() : InvalidFileTest() {} + virtual void HandlePeekResult(libvpx_test::Decoder *const decoder, + libvpx_test::CompressedVideoSource *video, + const vpx_codec_err_t res_peek) {} +}; + +TEST_P(InvalidFileInvalidPeekTest, ReturnCode) { + RunTest(); +} + +const DecodeParam kVP9InvalidFileInvalidPeekTests[] = { + {1, "invalid-vp90-01-v2.webm"}, +}; + +VP9_INSTANTIATE_TEST_CASE(InvalidFileInvalidPeekTest, + ::testing::ValuesIn(kVP9InvalidFileInvalidPeekTests)); + const DecodeParam kMultiThreadedVP9InvalidFileTests[] = { {4, "invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm"}, }; diff --git a/test/test-data.sha1 b/test/test-data.sha1 index d5a116558..aefa8a430 100644 --- a/test/test-data.sha1 +++ b/test/test-data.sha1 @@ -1,11 +1,19 @@ d5dfb0151c9051f8c85999255645d7a23916d3c0 hantro_collage_w352h288.yuv b87815bf86020c592ccc7a846ba2e28ec8043902 hantro_odd.yuv -fe346136b9b8c1e6f6084cc106485706915795e4 invalid-vp90-01.webm -25751f5d3b05ff03f0719ad42cd625348eb8961e invalid-vp90-01.webm.res -d78e2fceba5ac942246503ec8366f879c4775ca5 invalid-vp90-02.webm -2dadee5306245fa5eeb0f99652d0e17afbcba96d invalid-vp90-02.webm.res -df1a1453feb3c00d7d89746c7003b4163523bff3 invalid-vp90-03.webm -8fe6fd82bf537340f586f97a7ae31fb37ccda302 invalid-vp90-03.webm.res +76024eb753cdac6a5e5703aaea189d35c3c30ac7 invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf +7448d8798a4380162d4b56f9b452e2f6f9e24e7a invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf.res +83f50908c8dc0ef8760595447a2ff7727489542e invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf +456d1493e52d32a5c30edf44a27debc1fa6b253a invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf.res +c123d1f9f02fb4143abb5e271916e3a3080de8f6 invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf +456d1493e52d32a5c30edf44a27debc1fa6b253a invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf.res +fe346136b9b8c1e6f6084cc106485706915795e4 invalid-vp90-01-v2.webm +25751f5d3b05ff03f0719ad42cd625348eb8961e invalid-vp90-01-v2.webm.res +d78e2fceba5ac942246503ec8366f879c4775ca5 invalid-vp90-02-v2.webm +8e2eff4af87d2b561cce2365713269e301457ef3 invalid-vp90-02-v2.webm.res +df1a1453feb3c00d7d89746c7003b4163523bff3 invalid-vp90-03-v2.webm +25dd58c22d23f75304d7ce7f69f4e5b02ef9119a invalid-vp90-03-v2.webm.res +d637297561dd904eb2c97a9015deeb31c4a1e8d2 invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm +3a204bdbeaa3c6458b77bcebb8366d107267f55d invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm.res a432f96ff0a787268e2f94a8092ab161a18d1b06 park_joy_90p_10_420.y4m 0b194cc312c3a2e84d156a221b0a5eb615dfddc5 park_joy_90p_10_422.y4m ff0e0a21dc2adc95b8c1b37902713700655ced17 park_joy_90p_10_444.y4m @@ -657,17 +665,3 @@ e3ab35d4316c5e81325c50f5236ceca4bc0d35df vp90-2-15-segkey.webm.md5 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 -d3964f9dad9f60363c81b688324d95b4ec7c8038 invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.ivf.res -83f50908c8dc0ef8760595447a2ff7727489542e invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf -456d1493e52d32a5c30edf44a27debc1fa6b253a invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf.res -c123d1f9f02fb4143abb5e271916e3a3080de8f6 invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf -456d1493e52d32a5c30edf44a27debc1fa6b253a invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf.res -fe346136b9b8c1e6f6084cc106485706915795e4 invalid-vp90-01-v2.webm -25751f5d3b05ff03f0719ad42cd625348eb8961e invalid-vp90-01-v2.webm.res -d78e2fceba5ac942246503ec8366f879c4775ca5 invalid-vp90-02-v2.webm -8e2eff4af87d2b561cce2365713269e301457ef3 invalid-vp90-02-v2.webm.res -df1a1453feb3c00d7d89746c7003b4163523bff3 invalid-vp90-03-v2.webm -25dd58c22d23f75304d7ce7f69f4e5b02ef9119a invalid-vp90-03-v2.webm.res -d637297561dd904eb2c97a9015deeb31c4a1e8d2 invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm -3a204bdbeaa3c6458b77bcebb8366d107267f55d invalid-vp90-2-08-tile_1x4_frame_parallel_all_key.webm.res diff --git a/test/test.mk b/test/test.mk index f624649f0..c598d5196 100644 --- a/test/test.mk +++ b/test/test.mk @@ -783,8 +783,8 @@ LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-02-v2.webm LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-02-v2.webm.res LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-03-v2.webm LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-03-v2.webm.res -LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.ivf -LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.ivf.res +LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf +LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-00.webm.ivf.s5861_r01-05_b6-.v2.ivf.res LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-.ivf.res LIBVPX_TEST_DATA-$(CONFIG_VP9_DECODER) += invalid-vp90-2-00-quantizer-11.webm.ivf.s52984_r01-05_b6-z.ivf diff --git a/vp9/common/vp9_enums.h b/vp9/common/vp9_enums.h index 068284faa..53cf7f174 100644 --- a/vp9/common/vp9_enums.h +++ b/vp9/common/vp9_enums.h @@ -25,15 +25,18 @@ extern "C" { #define MI_MASK (MI_BLOCK_SIZE - 1) -// Bitstream profiles indicated by 2 bits in the uncompressed header. -// 00: Profile 0. 4:2:0 only. -// 10: Profile 1. adds 4:4:4, 4:2:2, alpha. -// 01: Profile 2. Supports 10-bit and 12-bit color only. -// 11: Undefined profile. +// Bitstream profiles indicated by 2-3 bits in the uncompressed header. +// 00: Profile 0. 8-bit 4:2:0 only. +// 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, with 4:2:0 sampling. +// 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 { PROFILE_0, PROFILE_1, PROFILE_2, + PROFILE_3, MAX_PROFILES } BITSTREAM_PROFILE; diff --git a/vp9/decoder/vp9_decodeframe.c b/vp9/decoder/vp9_decodeframe.c index 82d0307e0..76aee9d1b 100644 --- a/vp9/decoder/vp9_decodeframe.c +++ b/vp9/decoder/vp9_decodeframe.c @@ -1065,9 +1065,11 @@ int vp9_read_sync_code(struct vp9_read_bit_buffer *const rb) { vp9_rb_read_literal(rb, 8) == VP9_SYNC_CODE_2; } -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); profile |= vp9_rb_read_bit(rb) << 1; + if (profile > 2) + profile += vp9_rb_read_bit(rb); return (BITSTREAM_PROFILE) profile; } @@ -1083,7 +1085,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Invalid frame marker"); - cm->profile = read_profile(rb); + cm->profile = vp9_read_profile(rb); if (cm->profile >= MAX_PROFILES) vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, "Unsupported bitstream profile"); @@ -1118,7 +1120,7 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, 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 - if (cm->profile >= PROFILE_1) { + if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { cm->subsampling_x = vp9_rb_read_bit(rb); cm->subsampling_y = vp9_rb_read_bit(rb); vp9_rb_read_bit(rb); // has extra plane @@ -1126,12 +1128,12 @@ static size_t read_uncompressed_header(VP9Decoder *pbi, cm->subsampling_y = cm->subsampling_x = 1; } } else { - if (cm->profile >= PROFILE_1) { + if (cm->profile == PROFILE_1 || cm->profile == PROFILE_3) { cm->subsampling_y = cm->subsampling_x = 0; vp9_rb_read_bit(rb); // has extra plane } else { vpx_internal_error(&cm->error, VPX_CODEC_UNSUP_BITSTREAM, - "RGB not supported in profile 0"); + "4:4:4 color not supported in profile 0"); } } diff --git a/vp9/decoder/vp9_decodeframe.h b/vp9/decoder/vp9_decodeframe.h index e5d9d62dd..10a9e3462 100644 --- a/vp9/decoder/vp9_decodeframe.h +++ b/vp9/decoder/vp9_decodeframe.h @@ -29,6 +29,7 @@ void vp9_decode_frame(struct VP9Decoder *pbi, 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); +BITSTREAM_PROFILE vp9_read_profile(struct vp9_read_bit_buffer *rb); #ifdef __cplusplus } // extern "C" diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 1bf826a56..e2f2dfdf1 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -1024,9 +1024,22 @@ static void write_sync_code(struct vp9_write_bit_buffer *wb) { static void write_profile(BITSTREAM_PROFILE profile, struct vp9_write_bit_buffer *wb) { - assert(profile < MAX_PROFILES); - vp9_wb_write_bit(wb, profile & 1); - vp9_wb_write_bit(wb, profile >> 1); + switch (profile) { + case PROFILE_0: + vp9_wb_write_literal(wb, 0, 2); + break; + case PROFILE_1: + vp9_wb_write_literal(wb, 2, 2); + break; + case PROFILE_2: + vp9_wb_write_literal(wb, 1, 2); + break; + case PROFILE_3: + vp9_wb_write_literal(wb, 6, 3); + break; + default: + assert(0); + } } static void write_uncompressed_header(VP9_COMP *cpi, @@ -1052,13 +1065,13 @@ static void write_uncompressed_header(VP9_COMP *cpi, vp9_wb_write_literal(wb, cs, 3); if (cs != SRGB) { 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_y); vp9_wb_write_bit(wb, 0); // has extra plane } } else { - assert(cm->profile == PROFILE_1); + assert(cm->profile == PROFILE_1 || cm->profile == PROFILE_3); vp9_wb_write_bit(wb, 0); // has extra plane } diff --git a/vp9/vp9_dx_iface.c b/vp9/vp9_dx_iface.c index 259185250..4a23fdb71 100644 --- a/vp9/vp9_dx_iface.c +++ b/vp9/vp9_dx_iface.c @@ -122,13 +122,12 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, 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); - (void) vp9_rb_read_bit(&rb); // unused version bit + const BITSTREAM_PROFILE profile = vp9_read_profile(&rb); if (frame_marker != VP9_FRAME_MARKER) 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 vp9_rb_read_literal(&rb, 3); // Frame buffer to show. @@ -149,15 +148,17 @@ static vpx_codec_err_t decoder_peek_si_internal(const uint8_t *data, if (!vp9_read_sync_code(&rb)) 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); if (colorspace != sRGB) { 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 += 1; // has extra plane } } else { - if (version == 1) { + if (profile == PROFILE_1 || profile == PROFILE_3) { rb.bit_offset += 1; // has extra plane } else { // RGB is only available in version 1