From 9353607ac8fe2b0968d462e6e538f3f3e13204ef Mon Sep 17 00:00:00 2001 From: hkuang Date: Thu, 20 Nov 2014 15:39:56 -0800 Subject: [PATCH] Fix a bug that break the vp8 fragment decoder. (issue #882). Change-Id: I2ca7f96d390c4eaec0473c50cb01b903d0bd3ee6 --- test/codec_factory.h | 29 +++++++++++++++++++++++++++-- test/decode_test_driver.cc | 8 ++++++++ test/decode_test_driver.h | 21 ++++++++++++++++++--- test/encode_test_driver.cc | 17 ++++++++++++++++- test/encode_test_driver.h | 5 +++++ test/test.mk | 1 + test/vp8_fragments_test.cc | 37 +++++++++++++++++++++++++++++++++++++ vp8/vp8_dx_iface.c | 16 ++++++++-------- 8 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 test/vp8_fragments_test.cc diff --git a/test/codec_factory.h b/test/codec_factory.h index 7f9398c..3a0e3db 100644 --- a/test/codec_factory.h +++ b/test/codec_factory.h @@ -35,6 +35,11 @@ class CodecFactory { virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) const = 0; + virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, + const vpx_codec_flags_t flags, + unsigned long deadline) // NOLINT(runtime/int) + const = 0; + virtual Encoder* CreateEncoder(vpx_codec_enc_cfg_t cfg, unsigned long deadline, const unsigned long init_flags, @@ -72,6 +77,10 @@ class VP8Decoder : public Decoder { VP8Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) : Decoder(cfg, deadline) {} + VP8Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag, + unsigned long deadline) // NOLINT + : Decoder(cfg, flag, deadline) {} + protected: virtual vpx_codec_iface_t* CodecInterface() const { #if CONFIG_VP8_DECODER @@ -104,8 +113,14 @@ class VP8CodecFactory : public CodecFactory { virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) const { + return CreateDecoder(cfg, 0, deadline); + } + + virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, + const vpx_codec_flags_t flags, + unsigned long deadline) const { // NOLINT #if CONFIG_VP8_DECODER - return new VP8Decoder(cfg, deadline); + return new VP8Decoder(cfg, flags, deadline); #else return NULL; #endif @@ -154,6 +169,10 @@ class VP9Decoder : public Decoder { VP9Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) : Decoder(cfg, deadline) {} + VP9Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag, + unsigned long deadline) // NOLINT + : Decoder(cfg, flag, deadline) {} + protected: virtual vpx_codec_iface_t* CodecInterface() const { #if CONFIG_VP9_DECODER @@ -186,8 +205,14 @@ class VP9CodecFactory : public CodecFactory { virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) const { + return CreateDecoder(cfg, 0, deadline); + } + + virtual Decoder* CreateDecoder(vpx_codec_dec_cfg_t cfg, + const vpx_codec_flags_t flags, + unsigned long deadline) const { // NOLINT #if CONFIG_VP9_DECODER - return new VP9Decoder(cfg, deadline); + return new VP9Decoder(cfg, flags, deadline); #else return NULL; #endif diff --git a/test/decode_test_driver.cc b/test/decode_test_driver.cc index 0ef4f7b..852d90e 100644 --- a/test/decode_test_driver.cc +++ b/test/decode_test_driver.cc @@ -110,4 +110,12 @@ void DecoderTest::RunLoop(CompressedVideoSource *video) { RunLoop(video, dec_cfg); } +void DecoderTest::set_cfg(const vpx_codec_dec_cfg_t &dec_cfg) { + memcpy(&cfg_, &dec_cfg, sizeof(cfg_)); +} + +void DecoderTest::set_flags(const vpx_codec_flags_t flags) { + flags_ = flags; +} + } // namespace libvpx_test diff --git a/test/decode_test_driver.h b/test/decode_test_driver.h index 72a279f..f566c53 100644 --- a/test/decode_test_driver.h +++ b/test/decode_test_driver.h @@ -41,7 +41,13 @@ class DxDataIterator { class Decoder { public: Decoder(vpx_codec_dec_cfg_t cfg, unsigned long deadline) - : cfg_(cfg), deadline_(deadline), init_done_(false) { + : cfg_(cfg), flags_(0), deadline_(deadline), init_done_(false) { + memset(&decoder_, 0, sizeof(decoder_)); + } + + Decoder(vpx_codec_dec_cfg_t cfg, const vpx_codec_flags_t flag, + unsigned long deadline) // NOLINT + : cfg_(cfg), flags_(flag), deadline_(deadline), init_done_(false) { memset(&decoder_, 0, sizeof(decoder_)); } @@ -112,7 +118,7 @@ class Decoder { if (!init_done_) { const vpx_codec_err_t res = vpx_codec_dec_init(&decoder_, CodecInterface(), - &cfg_, 0); + &cfg_, flags_); ASSERT_EQ(VPX_CODEC_OK, res) << DecodeError(); init_done_ = true; } @@ -120,6 +126,7 @@ class Decoder { vpx_codec_ctx_t decoder_; vpx_codec_dec_cfg_t cfg_; + vpx_codec_flags_t flags_; unsigned int deadline_; bool init_done_; }; @@ -132,6 +139,9 @@ class DecoderTest { virtual void RunLoop(CompressedVideoSource *video, const vpx_codec_dec_cfg_t &dec_cfg); + virtual void set_cfg(const vpx_codec_dec_cfg_t &dec_cfg); + virtual void set_flags(const vpx_codec_flags_t flags); + // Hook to be called before decompressing every frame. virtual void PreDecodeFrameHook(const CompressedVideoSource& /*video*/, Decoder* /*decoder*/) {} @@ -154,11 +164,16 @@ class DecoderTest { const vpx_codec_err_t res_peek); protected: - explicit DecoderTest(const CodecFactory *codec) : codec_(codec) {} + explicit DecoderTest(const CodecFactory *codec) + : codec_(codec), + cfg_(), + flags_(0) {} virtual ~DecoderTest() {} const CodecFactory *codec_; + vpx_codec_dec_cfg_t cfg_; + vpx_codec_flags_t flags_; }; } // namespace libvpx_test diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc index 5b6757c..b49e8cb 100644 --- a/test/encode_test_driver.cc +++ b/test/encode_test_driver.cc @@ -140,6 +140,8 @@ void EncoderTest::MismatchHook(const vpx_image_t* /*img1*/, } void EncoderTest::RunLoop(VideoSource *video) { + vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); + stats_.Reset(); ASSERT_TRUE(passes_ == 1 || passes_ == 2); @@ -157,7 +159,13 @@ void EncoderTest::RunLoop(VideoSource *video) { Encoder* const encoder = codec_->CreateEncoder(cfg_, deadline_, init_flags_, &stats_); ASSERT_TRUE(encoder != NULL); - Decoder* const decoder = codec_->CreateDecoder(dec_cfg_, 0); + + unsigned long dec_init_flags = 0; // NOLINT + // Use fragment decoder if encoder outputs partitions. + // NOTE: fragment decoder and partition encoder are only supported by VP8. + if (init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) + dec_init_flags |= VPX_CODEC_USE_INPUT_FRAGMENTS; + Decoder* const decoder = codec_->CreateDecoder(dec_cfg, dec_init_flags, 0); bool again; for (again = true, video->Begin(); again; video->Next()) { again = (video->img() != NULL); @@ -199,6 +207,13 @@ void EncoderTest::RunLoop(VideoSource *video) { } } + // Flush the decoder when there are no more fragments. + if ((init_flags_ & VPX_CODEC_USE_OUTPUT_PARTITION) && has_dxdata) { + const vpx_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0); + if (!HandleDecodeResult(res_dec, *video, decoder)) + break; + } + if (has_dxdata && has_cxdata) { const vpx_image_t *img_enc = encoder->GetPreviewFrame(); DxDataIterator dec_iter = decoder->GetDxData(); diff --git a/test/encode_test_driver.h b/test/encode_test_driver.h index 3bc7847..770ac7e 100644 --- a/test/encode_test_driver.h +++ b/test/encode_test_driver.h @@ -185,6 +185,11 @@ class EncoderTest { // Map the TestMode enum to the deadline_ and passes_ variables. void SetMode(TestMode mode); + // Set encoder flag. + void set_init_flags(unsigned long flag) { // NOLINT(runtime/int) + init_flags_ = flag; + } + // Main loop virtual void RunLoop(VideoSource *video); diff --git a/test/test.mk b/test/test.mk index f5c9c37..bd65759 100644 --- a/test/test.mk +++ b/test/test.mk @@ -95,6 +95,7 @@ ifneq ($(CONFIG_VP8_ENCODER)$(CONFIG_VP8_DECODER),) # These tests require both the encoder and decoder to be built. ifeq ($(CONFIG_VP8_ENCODER)$(CONFIG_VP8_DECODER),yesyes) LIBVPX_TEST_SRCS-yes += vp8_boolcoder_test.cc +LIBVPX_TEST_SRCS-yes += vp8_fragments_test.cc endif LIBVPX_TEST_SRCS-$(CONFIG_POSTPROC) += pp_filter_test.cc diff --git a/test/vp8_fragments_test.cc b/test/vp8_fragments_test.cc new file mode 100644 index 0000000..cb0d1a1 --- /dev/null +++ b/test/vp8_fragments_test.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "third_party/googletest/src/include/gtest/gtest.h" +#include "test/codec_factory.h" +#include "test/video_source.h" + +namespace { + +class VP8FramgmentsTest + : public ::libvpx_test::EncoderTest, + public ::testing::Test { + protected: + VP8FramgmentsTest() : EncoderTest(&::libvpx_test::kVP8) {} + virtual ~VP8FramgmentsTest() {} + + virtual void SetUp() { + const unsigned long init_flags = // NOLINT(runtime/int) + VPX_CODEC_USE_OUTPUT_PARTITION; + InitializeConfig(); + SetMode(::libvpx_test::kRealTime); + set_init_flags(init_flags); + } +}; + +TEST_F(VP8FramgmentsTest, TestFragmentsEncodeDecode) { + ::libvpx_test::RandomVideoSource video; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + +} // namespace diff --git a/vp8/vp8_dx_iface.c b/vp8/vp8_dx_iface.c index 5aa274d..352ed7b 100644 --- a/vp8/vp8_dx_iface.c +++ b/vp8/vp8_dx_iface.c @@ -60,7 +60,6 @@ struct vpx_codec_alg_priv vpx_decrypt_cb decrypt_cb; void *decrypt_state; vpx_image_t img; - int flushed; int img_setup; struct frame_buffers yv12_frame_buffers; void *user_priv; @@ -89,7 +88,6 @@ static void vp8_init_ctx(vpx_codec_ctx_t *ctx) priv->si.sz = sizeof(priv->si); priv->decrypt_cb = NULL; priv->decrypt_state = NULL; - priv->flushed = 0; if (ctx->config.dec) { @@ -307,6 +305,11 @@ update_fragments(vpx_codec_alg_priv_t *ctx, return 0; } + if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) + { + return 0; + } + if (!ctx->fragments.enabled) { ctx->fragments.ptrs[0] = data; @@ -327,14 +330,11 @@ static vpx_codec_err_t vp8_decode(vpx_codec_alg_priv_t *ctx, unsigned int resolution_change = 0; unsigned int w, h; - if (data == NULL && data_sz == 0) { - ctx->flushed = 1; - return VPX_CODEC_OK; + if (!ctx->fragments.enabled && (data == NULL && data_sz == 0)) + { + return 0; } - /* Reset flushed when receiving a valid frame */ - ctx->flushed = 0; - /* Update the input fragment data */ if(update_fragments(ctx, data, data_sz, &res) <= 0) return res; -- 2.7.4