diff --git a/test/decode_test_driver.cc b/test/decode_test_driver.cc index ad861c315..7fb3e379d 100644 --- a/test/decode_test_driver.cc +++ b/test/decode_test_driver.cc @@ -18,6 +18,7 @@ namespace libvpx_test { const char kVP8Name[] = "WebM Project VP8"; +const char kVP10Name[] = "WebM Project VP10"; vpx_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size, vpx_codec_stream_info_t *stream_info) { @@ -46,6 +47,11 @@ bool Decoder::IsVP8() const { return strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0; } +bool Decoder::IsVP10() const { + const char *codec_name = GetDecoderName(); + return strncmp(kVP10Name, codec_name, sizeof(kVP10Name) - 1) == 0; +} + void DecoderTest::HandlePeekResult(Decoder *const decoder, CompressedVideoSource *video, const vpx_codec_err_t res_peek) { diff --git a/test/decode_test_driver.h b/test/decode_test_driver.h index f566c53c7..1492c5ad7 100644 --- a/test/decode_test_driver.h +++ b/test/decode_test_driver.h @@ -107,6 +107,8 @@ class Decoder { bool IsVP8() const; + bool IsVP10() const; + vpx_codec_ctx_t * GetDecoder() { return &decoder_; } diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc index e24c9bfb6..f3c324311 100644 --- a/test/encode_test_driver.cc +++ b/test/encode_test_driver.cc @@ -56,7 +56,7 @@ void Encoder::InitEncoder(VideoSource *video) { #endif // !CONFIG_EXT_TILE } else #endif - { + if (CodecInterface() == &vpx_codec_vp8_cx_algo) { #if CONFIG_VP8_ENCODER ASSERT_EQ(&vpx_codec_vp8_cx_algo, CodecInterface()) << "Unknown Codec Interface"; @@ -261,12 +261,6 @@ void EncoderTest::MismatchHook(const vpx_image_t* img_enc, void EncoderTest::RunLoop(VideoSource *video) { vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); -#if CONFIG_EXT_TILE - // Decode all tiles. - dec_cfg.tile_col = -1; - dec_cfg.tile_row = -1; -#endif // CONFIG_EXT_TILE - stats_.Reset(); ASSERT_TRUE(passes_ == 1 || passes_ == 2); @@ -295,6 +289,15 @@ void EncoderTest::RunLoop(VideoSource *video) { 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); +#if CONFIG_VP10 && CONFIG_EXT_TILE + if (decoder->IsVP10()) { + // Set dec_cfg.tile_row = -1 and dec_cfg.tile_col = -1 so that the whole + // frame is decoded. + decoder->Control(VP10_SET_DECODE_TILE_ROW, -1); + decoder->Control(VP10_SET_DECODE_TILE_COL, -1); + } +#endif + bool again; for (again = true; again; video->Next()) { again = (video->img() != NULL); diff --git a/test/svc_test.cc b/test/svc_test.cc index e573e10ed..1ad17be86 100644 --- a/test/svc_test.cc +++ b/test/svc_test.cc @@ -61,12 +61,14 @@ class SvcTest : public ::testing::Test { codec_enc_.kf_max_dist = 100; vpx_codec_dec_cfg_t dec_cfg = vpx_codec_dec_cfg_t(); -#if CONFIG_EXT_TILE - dec_cfg.tile_col = -1; - dec_cfg.tile_row = -1; -#endif // CONFIG_EXT_TILE VP9CodecFactory codec_factory; decoder_ = codec_factory.CreateDecoder(dec_cfg, 0); +#if CONFIG_VP10 && CONFIG_EXT_TILE + if (decoder_->IsVP10()) { + decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1); + decoder_->Control(VP10_SET_DECODE_TILE_COL, -1); + } +#endif tile_columns_ = 0; tile_rows_ = 0; diff --git a/test/test.mk b/test/test.mk index 59f054cfa..7412b27a0 100644 --- a/test/test.mk +++ b/test/test.mk @@ -170,6 +170,7 @@ LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += vp10_fht4x4_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += vp10_fht8x8_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += vp10_fht16x16_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ANS) += vp10_ans_test.cc +LIBVPX_TEST_SRCS-$(CONFIG_EXT_TILE) += vp10_ext_tile_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += sum_squares_test.cc LIBVPX_TEST_SRCS-$(CONFIG_VP10_ENCODER) += subtract_test.cc diff --git a/test/tile_independence_test.cc b/test/tile_independence_test.cc index 9a049bf9d..dc31d0670 100644 --- a/test/tile_independence_test.cc +++ b/test/tile_independence_test.cc @@ -35,13 +35,18 @@ class TileIndependenceTest : public ::libvpx_test::EncoderTest, cfg.w = 704; cfg.h = 144; cfg.threads = 1; -#if CONFIG_EXT_TILE - cfg.tile_col = -1; - cfg.tile_row = -1; -#endif // CONFIG_EXT_TILE fw_dec_ = codec_->CreateDecoder(cfg, 0); inv_dec_ = codec_->CreateDecoder(cfg, 0); inv_dec_->Control(VP9_INVERT_TILE_DECODE_ORDER, 1); + +#if CONFIG_VP10 && CONFIG_EXT_TILE + if (fw_dec_->IsVP10() && inv_dec_->IsVP10()) { + fw_dec_->Control(VP10_SET_DECODE_TILE_ROW, -1); + fw_dec_->Control(VP10_SET_DECODE_TILE_COL, -1); + inv_dec_->Control(VP10_SET_DECODE_TILE_ROW, -1); + inv_dec_->Control(VP10_SET_DECODE_TILE_COL, -1); + } +#endif } virtual ~TileIndependenceTest() { diff --git a/test/vp10_ext_tile_test.cc b/test/vp10_ext_tile_test.cc new file mode 100644 index 000000000..7c9e960e9 --- /dev/null +++ b/test/vp10_ext_tile_test.cc @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include "third_party/googletest/src/include/gtest/gtest.h" +#include "test/codec_factory.h" +#include "test/encode_test_driver.h" +#include "test/i420_video_source.h" +#include "test/md5_helper.h" +#include "test/util.h" + +namespace { +// The number of frames to be encoded/decoded +const int kLimit = 8; +// Skip 1 frame to check the frame decoding independency. +const int kSkip = 5; +const int kTileSize = 1; +const int kTIleSizeInPixels = (kTileSize << 6); +// Fake width and height so that they can be multiples of the tile size. +const int kImgWidth = 704; +const int kImgHeight = 576; + +class VP10ExtTileTest + : public ::libvpx_test::EncoderTest, + public ::libvpx_test::CodecTestWith2Params { + protected: + VP10ExtTileTest() + : EncoderTest(GET_PARAM(0)), + encoding_mode_(GET_PARAM(1)), + set_cpu_used_(GET_PARAM(2)) { + init_flags_ = VPX_CODEC_USE_PSNR; + vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t(); + cfg.w = kImgWidth; + cfg.h = kImgHeight; + + decoder_ = codec_->CreateDecoder(cfg, 0); + decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1); + decoder_->Control(VP10_SET_DECODE_TILE_COL, -1); + + // Allocate buffer to store tile image. + vpx_img_alloc(&tile_img_, VPX_IMG_FMT_I420, kImgWidth, kImgHeight, 32); + + md5_.clear(); + tile_md5_.clear(); + } + + virtual ~VP10ExtTileTest() { + vpx_img_free(&tile_img_); + delete decoder_; + } + + virtual void SetUp() { + InitializeConfig(); + SetMode(encoding_mode_); + + cfg_.g_lag_in_frames = 0; + cfg_.rc_end_usage = VPX_VBR; + cfg_.g_error_resilient = 1; + + cfg_.rc_max_quantizer = 56; + cfg_.rc_min_quantizer = 0; + } + + virtual void PreEncodeFrameHook(::libvpx_test::VideoSource * video, + ::libvpx_test::Encoder *encoder) { + if (video->frame() == 0) { + // Encode setting + encoder->Control(VP8E_SET_CPUUSED, set_cpu_used_); + encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 0); + encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1); + + // The tile size is 64x64. + encoder->Control(VP9E_SET_TILE_COLUMNS, kTileSize); + encoder->Control(VP9E_SET_TILE_ROWS, kTileSize); +#if CONFIG_EXT_PARTITION + // Always use 64x64 max partition. + encoder->Control(VP10E_SET_SUPERBLOCK_SIZE, VPX_SUPERBLOCK_SIZE_64X64); +#endif + } + + if (video->frame() == 1) { + frame_flags_ = VP8_EFLAG_NO_UPD_LAST | VP8_EFLAG_NO_UPD_GF | + VP8_EFLAG_NO_UPD_ARF; + } + } + + virtual void DecompressedFrameHook(const vpx_image_t &img, + vpx_codec_pts_t pts) { + // Skip 1 already decoded frame to be consistent with the decoder in this + // test. + if (pts == (vpx_codec_pts_t)kSkip) + return; + + // Calculate MD5 as the reference. + ::libvpx_test::MD5 md5_res; + md5_res.Add(&img); + md5_.push_back(md5_res.Get()); + } + + virtual void FramePktHook(const vpx_codec_cx_pkt_t *pkt) { + // Skip decoding 1 frame. + if (pkt->data.frame.pts == (vpx_codec_pts_t)kSkip) + return; + + bool IsLastFrame = (pkt->data.frame.pts == (vpx_codec_pts_t)(kLimit - 1)); + + // Decode the first (kLimit - 1) frames as whole frame, and decode the last + // frame in single tiles. + for (int r = 0; r < kImgHeight / kTIleSizeInPixels; ++r) { + for (int c = 0; c < kImgWidth / kTIleSizeInPixels; ++c) { + if (!IsLastFrame) { + decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1); + decoder_->Control(VP10_SET_DECODE_TILE_COL, -1); + } else { + decoder_->Control(VP10_SET_DECODE_TILE_ROW, r); + decoder_->Control(VP10_SET_DECODE_TILE_COL, c); + } + + const vpx_codec_err_t res = decoder_->DecodeFrame( + reinterpret_cast(pkt->data.frame.buf), + pkt->data.frame.sz); + if (res != VPX_CODEC_OK) { + abort_ = true; + ASSERT_EQ(VPX_CODEC_OK, res); + } + const vpx_image_t *img = decoder_->GetDxData().Next(); + + if (!IsLastFrame) { + if (img) { + ::libvpx_test::MD5 md5_res; + md5_res.Add(img); + tile_md5_.push_back(md5_res.Get()); + } + break; + } + + const int kMaxMBPlane = 3; + for (int plane = 0; plane < kMaxMBPlane; ++plane) { + const int shift = (plane == 0) ? 0 : 1; + int tile_height = kTIleSizeInPixels >> shift; + int tile_width = kTIleSizeInPixels >> shift; + + for (int tr = 0; tr < tile_height; ++tr) { + memcpy(tile_img_.planes[plane] + + tile_img_.stride[plane] * (r * tile_height + tr) + + c * tile_width, + img->planes[plane] + img->stride[plane] * tr, tile_width); + } + } + } + + if (!IsLastFrame) + break; + } + + if (IsLastFrame && &tile_img_) { + ::libvpx_test::MD5 md5_res; + md5_res.Add(&tile_img_); + tile_md5_.push_back(md5_res.Get()); + } + } + + ::libvpx_test::TestMode encoding_mode_; + int set_cpu_used_; + ::libvpx_test::Decoder *decoder_; + vpx_image_t tile_img_; + std::vector md5_; + std::vector tile_md5_; +}; + +TEST_P(VP10ExtTileTest, DecoderResultTest) { + ::libvpx_test::I420VideoSource video("hantro_collage_w352h288.yuv", + kImgWidth, kImgHeight, 30, 1, 0, kLimit); + cfg_.rc_target_bitrate = 500; + cfg_.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; + cfg_.g_lag_in_frames = 0; + cfg_.g_threads = 1; + + // Tile encoding + init_flags_ = VPX_CODEC_USE_PSNR; + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); + + // Compare to check if two vectors are equal. + ASSERT_EQ(md5_, tile_md5_); +} + +VP10_INSTANTIATE_TEST_CASE( + // Now only test 2-pass mode. + VP10ExtTileTest, + ::testing::Values(::libvpx_test::kTwoPassGood), + ::testing::Range(0, 4)); +} // namespace diff --git a/test/vp9_ethread_test.cc b/test/vp9_ethread_test.cc index d6b6951fa..35a6619d7 100644 --- a/test/vp9_ethread_test.cc +++ b/test/vp9_ethread_test.cc @@ -33,11 +33,13 @@ class VPxEncoderThreadTest vpx_codec_dec_cfg_t cfg = vpx_codec_dec_cfg_t(); cfg.w = 1280; cfg.h = 720; -#if CONFIG_EXT_TILE - cfg.tile_col = -1; - cfg.tile_row = -1; -#endif // CONFIG_EXT_TILE decoder_ = codec_->CreateDecoder(cfg, 0); +#if CONFIG_VP10 && CONFIG_EXT_TILE + if (decoder_->IsVP10()) { + decoder_->Control(VP10_SET_DECODE_TILE_ROW, -1); + decoder_->Control(VP10_SET_DECODE_TILE_COL, -1); + } +#endif size_enc_.clear(); md5_dec_.clear(); diff --git a/vp10/vp10_dx_iface.c b/vp10/vp10_dx_iface.c index cf6ab5661..8dc49f237 100644 --- a/vp10/vp10_dx_iface.c +++ b/vp10/vp10_dx_iface.c @@ -58,6 +58,8 @@ struct vpx_codec_alg_priv { int last_show_frame; // Index of last output frame. int byte_alignment; int skip_loop_filter; + int decode_tile_row; + int decode_tile_col; // Frame parallel related. int frame_parallel_decode; // frame-based threading. @@ -501,8 +503,8 @@ static vpx_codec_err_t decode_one(vpx_codec_alg_priv_t *ctx, frame_worker_data->pbi->decrypt_state = ctx->decrypt_state; #if CONFIG_EXT_TILE - frame_worker_data->pbi->dec_tile_row = ctx->cfg.tile_row; - frame_worker_data->pbi->dec_tile_col = ctx->cfg.tile_col; + frame_worker_data->pbi->dec_tile_row = ctx->decode_tile_row; + frame_worker_data->pbi->dec_tile_col = ctx->decode_tile_col; #endif // CONFIG_EXT_TILE worker->had_error = 0; @@ -1118,6 +1120,18 @@ static vpx_codec_err_t ctrl_set_skip_loop_filter(vpx_codec_alg_priv_t *ctx, return VPX_CODEC_OK; } +static vpx_codec_err_t ctrl_set_decode_tile_row(vpx_codec_alg_priv_t *ctx, + va_list args) { + ctx->decode_tile_row = va_arg(args, int); + return VPX_CODEC_OK; +} + +static vpx_codec_err_t ctrl_set_decode_tile_col(vpx_codec_alg_priv_t *ctx, + va_list args) { + ctx->decode_tile_col = va_arg(args, int); + return VPX_CODEC_OK; +} + static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = { {VP8_COPY_REFERENCE, ctrl_copy_reference}, @@ -1132,6 +1146,8 @@ static vpx_codec_ctrl_fn_map_t decoder_ctrl_maps[] = { {VPXD_SET_DECRYPTOR, ctrl_set_decryptor}, {VP9_SET_BYTE_ALIGNMENT, ctrl_set_byte_alignment}, {VP9_SET_SKIP_LOOP_FILTER, ctrl_set_skip_loop_filter}, + {VP10_SET_DECODE_TILE_ROW, ctrl_set_decode_tile_row}, + {VP10_SET_DECODE_TILE_COL, ctrl_set_decode_tile_col}, // Getters {VP8D_GET_LAST_REF_UPDATES, ctrl_get_last_ref_updates}, diff --git a/vpx/vp8dx.h b/vpx/vp8dx.h index 1f02fd595..347521ee2 100644 --- a/vpx/vp8dx.h +++ b/vpx/vp8dx.h @@ -121,7 +121,16 @@ enum vp8_dec_control_id { */ VP9_SET_SKIP_LOOP_FILTER, - VP8_DECODER_CTRL_ID_MAX + VP8_DECODER_CTRL_ID_MAX, + + /** control function to set the range of tile decoding. A value that is + * greater and equal to zero indicates only the specific row/column is + * decoded. A value that is -1 indicates the whole row/column is decoded. + * A special case is both values are -1 that means the whole frame is + * decoded. + */ + VP10_SET_DECODE_TILE_ROW, + VP10_SET_DECODE_TILE_COL }; /** Decrypt n bytes of data from input -> output, using the decrypt_state @@ -174,7 +183,10 @@ VPX_CTRL_USE_TYPE(VP9D_GET_FRAME_SIZE, int *) #define VPX_CTRL_VP9D_GET_FRAME_SIZE VPX_CTRL_USE_TYPE(VP9_INVERT_TILE_DECODE_ORDER, int) #define VPX_CTRL_VP9_INVERT_TILE_DECODE_ORDER - +VPX_CTRL_USE_TYPE(VP10_SET_DECODE_TILE_ROW, int) +#define VPX_CTRL_VP10_SET_DECODE_TILE_ROW +VPX_CTRL_USE_TYPE(VP10_SET_DECODE_TILE_COL, int) +#define VPX_CTRL_VP10_SET_DECODE_TILE_COL /*!\endcond */ /*! @} - end defgroup vp8_decoder */ diff --git a/vpx/vpx_decoder.h b/vpx/vpx_decoder.h index d4ba98685..62fd91975 100644 --- a/vpx/vpx_decoder.h +++ b/vpx/vpx_decoder.h @@ -108,10 +108,6 @@ extern "C" { unsigned int threads; /**< Maximum number of threads to use, default 1 */ unsigned int w; /**< Width */ unsigned int h; /**< Height */ - int tile_row; /**< The index of row tile to be decoded. - Value -1 means to decode all row tiles. */ - int tile_col; /**< The index of column tile to be decoded. - Value -1 means to decode all column tiles */ } vpx_codec_dec_cfg_t; /**< alias for struct vpx_codec_dec_cfg */ diff --git a/vpxdec.c b/vpxdec.c index 13b020b95..235d17a9f 100644 --- a/vpxdec.c +++ b/vpxdec.c @@ -818,11 +818,6 @@ static int main_loop(int argc, const char **argv_) { if (!interface) interface = get_vpx_decoder_by_index(0); -#if CONFIG_EXT_TILE - cfg.tile_row = tile_row; - cfg.tile_col = tile_col; -#endif // CONFIG_EXT_TILE - dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0) | (frame_parallel ? VPX_CODEC_USE_FRAME_THREADING : 0); @@ -877,6 +872,21 @@ static int main_loop(int argc, const char **argv_) { } #endif +#if CONFIG_VP10_DECODER && CONFIG_EXT_TILE + if (strncmp(decoder.name, "WebM Project VP10", 17) == 0) { + if (vpx_codec_control(&decoder, VP10_SET_DECODE_TILE_ROW, tile_row)) { + fprintf(stderr, "Failed to set decode_tile_row: %s\n", + vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + + if (vpx_codec_control(&decoder, VP10_SET_DECODE_TILE_COL, tile_col)) { + fprintf(stderr, "Failed to set decode_tile_col: %s\n", + vpx_codec_error(&decoder)); + return EXIT_FAILURE; + } + } +#endif if (arg_skip) fprintf(stderr, "Skipping first %d frames.\n", arg_skip); diff --git a/vpxenc.c b/vpxenc.c index 7fb28cded..9a52d542c 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -1580,8 +1580,18 @@ static void initialize_encoder(struct stream_state *stream, #if CONFIG_DECODERS if (global->test_decode != TEST_DECODE_OFF) { const VpxInterface *decoder = get_vpx_decoder_by_name(global->codec->name); - vpx_codec_dec_cfg_t cfg = { 0, 0, 0, -1, -1 }; + vpx_codec_dec_cfg_t cfg = { 0, 0, 0}; vpx_codec_dec_init(&stream->decoder, decoder->codec_interface(), &cfg, 0); + +#if CONFIG_VP10_DECODER && CONFIG_EXT_TILE + if (strcmp(global->codec->name, "vp10") == 0) { + vpx_codec_control(&stream->decoder, VP10_SET_DECODE_TILE_ROW, -1); + ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_row"); + + vpx_codec_control(&stream->decoder, VP10_SET_DECODE_TILE_COL, -1); + ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_col"); + } +#endif } #endif }