Migrate software decoders to new VideoDecoder::Configure

Bug: webrtc:13045
Change-Id: I1fa28a7c2dd59f0889d98c8ec5f58161c0ec9f95
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/228380
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34716}
This commit is contained in:
Danil Chapovalov
2021-08-10 14:33:31 +02:00
committed by WebRTC LUCI CQ
parent bf75041b8d
commit 53d4be223b
14 changed files with 98 additions and 110 deletions

View File

@ -17,7 +17,6 @@
#include "api/scoped_refptr.h"
#include "api/video/encoded_image.h"
#include "api/video/i420_buffer.h"
#include "api/video_codecs/video_codec.h"
#include "api/video_codecs/video_decoder.h"
#include "common_video/include/video_frame_buffer_pool.h"
#include "modules/video_coding/include/video_error_codes.h"
@ -40,8 +39,7 @@ class LibaomAv1Decoder final : public VideoDecoder {
~LibaomAv1Decoder();
// Implements VideoDecoder.
int32_t InitDecode(const VideoCodec* codec_settings,
int number_of_cores) override;
bool Configure(const Settings& settings) override;
// Decode an encoded video frame.
int32_t Decode(const EncodedImage& encoded_image,
@ -74,23 +72,20 @@ LibaomAv1Decoder::~LibaomAv1Decoder() {
Release();
}
int32_t LibaomAv1Decoder::InitDecode(const VideoCodec* codec_settings,
int number_of_cores) {
aom_codec_dec_cfg_t config = {
static_cast<unsigned int>(number_of_cores), // Max # of threads.
0, // Frame width set after decode.
0, // Frame height set after decode.
kConfigLowBitDepth}; // Enable low-bit-depth code path.
bool LibaomAv1Decoder::Configure(const Settings& settings) {
aom_codec_dec_cfg_t config = {};
config.threads = static_cast<unsigned int>(settings.number_of_cores());
config.allow_lowbitdepth = kConfigLowBitDepth;
aom_codec_err_t ret =
aom_codec_dec_init(&context_, aom_codec_av1_dx(), &config, kDecFlags);
if (ret != AOM_CODEC_OK) {
RTC_LOG(LS_WARNING) << "LibaomAv1Decoder::InitDecode returned " << ret
RTC_LOG(LS_WARNING) << "LibaomAv1Decoder::Configure returned " << ret
<< " on aom_codec_dec_init.";
return WEBRTC_VIDEO_CODEC_ERROR;
return false;
}
inited_ = true;
return WEBRTC_VIDEO_CODEC_OK;
return true;
}
int32_t LibaomAv1Decoder::Decode(const EncodedImage& encoded_image,

View File

@ -77,9 +77,7 @@ class TestAv1Decoder {
ADD_FAILURE() << "Failed to create a decoder#" << decoder_id_;
return;
}
EXPECT_EQ(decoder_->InitDecode(/*codec_settings=*/nullptr,
/*number_of_cores=*/1),
WEBRTC_VIDEO_CODEC_OK);
EXPECT_TRUE(decoder_->Configure({}));
EXPECT_EQ(decoder_->RegisterDecodeCompleteCallback(&callback_),
WEBRTC_VIDEO_CODEC_OK);
}

View File

@ -69,9 +69,9 @@ ScopedAVPacket MakeScopedAVPacket() {
int H264DecoderImpl::AVGetBuffer2(AVCodecContext* context,
AVFrame* av_frame,
int flags) {
// Set in `InitDecode`.
// Set in `Configure`.
H264DecoderImpl* decoder = static_cast<H264DecoderImpl*>(context->opaque);
// DCHECK values set in `InitDecode`.
// DCHECK values set in `Configure`.
RTC_DCHECK(decoder);
// Necessary capability to be allowed to provide our own buffers.
RTC_DCHECK(context->codec->capabilities | AV_CODEC_CAP_DR1);
@ -172,19 +172,18 @@ H264DecoderImpl::~H264DecoderImpl() {
Release();
}
int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
int32_t number_of_cores) {
bool H264DecoderImpl::Configure(const Settings& settings) {
ReportInit();
if (codec_settings && codec_settings->codecType != kVideoCodecH264) {
if (settings.codec_type() != kVideoCodecH264) {
ReportError();
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
return false;
}
// Release necessary in case of re-initializing.
int32_t ret = Release();
if (ret != WEBRTC_VIDEO_CODEC_OK) {
ReportError();
return ret;
return false;
}
RTC_DCHECK(!av_context_);
@ -193,9 +192,10 @@ int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
av_context_->codec_type = AVMEDIA_TYPE_VIDEO;
av_context_->codec_id = AV_CODEC_ID_H264;
if (codec_settings) {
av_context_->coded_width = codec_settings->width;
av_context_->coded_height = codec_settings->height;
const RenderResolution& resolution = settings.max_render_resolution();
if (resolution.Valid()) {
av_context_->coded_width = resolution.Width();
av_context_->coded_height = resolution.Height();
}
av_context_->pix_fmt = kPixelFormatDefault;
av_context_->extradata = nullptr;
@ -219,25 +219,25 @@ int32_t H264DecoderImpl::InitDecode(const VideoCodec* codec_settings,
RTC_LOG(LS_ERROR) << "FFmpeg H.264 decoder not found.";
Release();
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
return false;
}
int res = avcodec_open2(av_context_.get(), codec, nullptr);
if (res < 0) {
RTC_LOG(LS_ERROR) << "avcodec_open2 error: " << res;
Release();
ReportError();
return WEBRTC_VIDEO_CODEC_ERROR;
return false;
}
av_frame_.reset(av_frame_alloc());
if (codec_settings && codec_settings->buffer_pool_size) {
if (!ffmpeg_buffer_pool_.Resize(*codec_settings->buffer_pool_size) ||
!output_buffer_pool_.Resize(*codec_settings->buffer_pool_size)) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
if (absl::optional<int> buffer_pool_size = settings.buffer_pool_size()) {
if (!ffmpeg_buffer_pool_.Resize(*buffer_pool_size) ||
!output_buffer_pool_.Resize(*buffer_pool_size)) {
return false;
}
}
return WEBRTC_VIDEO_CODEC_OK;
return true;
}
int32_t H264DecoderImpl::Release() {
@ -261,7 +261,7 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image,
}
if (!decoded_image_callback_) {
RTC_LOG(LS_WARNING)
<< "InitDecode() has been called, but a callback function "
<< "Configure() has been called, but a callback function "
"has not been set with RegisterDecodeCompleteCallback()";
ReportError();
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;

View File

@ -60,10 +60,7 @@ class H264DecoderImpl : public H264Decoder {
H264DecoderImpl();
~H264DecoderImpl() override;
// If `codec_settings` is NULL it is ignored. If it is not NULL,
// `codec_settings->codecType` must be `kVideoCodecH264`.
int32_t InitDecode(const VideoCodec* codec_settings,
int32_t number_of_cores) override;
bool Configure(const Settings& settings) override;
int32_t Release() override;
int32_t RegisterDecodeCompleteCallback(

View File

@ -31,8 +31,7 @@ class MultiplexDecoderAdapter : public VideoDecoder {
virtual ~MultiplexDecoderAdapter();
// Implements VideoDecoder
int32_t InitDecode(const VideoCodec* codec_settings,
int32_t number_of_cores) override;
bool Configure(const Settings& settings) override;
int32_t Decode(const EncodedImage& input_image,
bool missing_frames,
int64_t render_time_ms) override;

View File

@ -104,24 +104,24 @@ MultiplexDecoderAdapter::~MultiplexDecoderAdapter() {
Release();
}
int32_t MultiplexDecoderAdapter::InitDecode(const VideoCodec* codec_settings,
int32_t number_of_cores) {
RTC_DCHECK_EQ(kVideoCodecMultiplex, codec_settings->codecType);
VideoCodec settings = *codec_settings;
settings.codecType = PayloadStringToCodecType(associated_format_.name);
bool MultiplexDecoderAdapter::Configure(const Settings& settings) {
RTC_DCHECK_EQ(settings.codec_type(), kVideoCodecMultiplex);
Settings associated_settings = settings;
associated_settings.set_codec_type(
PayloadStringToCodecType(associated_format_.name));
for (size_t i = 0; i < kAlphaCodecStreams; ++i) {
std::unique_ptr<VideoDecoder> decoder =
factory_->CreateVideoDecoder(associated_format_);
const int32_t rv = decoder->InitDecode(&settings, number_of_cores);
if (rv)
return rv;
if (!decoder->Configure(associated_settings)) {
return false;
}
adapter_callbacks_.emplace_back(
new MultiplexDecoderAdapter::AdapterDecodedImageCallback(
this, static_cast<AlphaCodecStream>(i)));
decoder->RegisterDecodeCompleteCallback(adapter_callbacks_.back().get());
decoders_.emplace_back(std::move(decoder));
}
return WEBRTC_VIDEO_CODEC_OK;
return true;
}
int32_t MultiplexDecoderAdapter::Decode(const EncodedImage& input_image,

View File

@ -87,8 +87,12 @@ void VideoCodecUnitTest::SetUp() {
&codec_settings_,
VideoEncoder::Settings(kCapabilities, 1 /* number of cores */,
0 /* max payload size (unused) */)));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
decoder_->InitDecode(&codec_settings_, 1 /* number of cores */));
VideoDecoder::Settings decoder_settings;
decoder_settings.set_codec_type(codec_settings_.codecType);
decoder_settings.set_max_render_resolution(
{codec_settings_.width, codec_settings_.height});
EXPECT_TRUE(decoder_->Configure(decoder_settings));
}
void VideoCodecUnitTest::ModifyCodecSettings(VideoCodec* codec_settings) {}

View File

@ -21,6 +21,7 @@
#elif defined(WEBRTC_IOS)
#include "modules/video_coding/codecs/test/objc_codec_factory_helper.h"
#endif
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/video_codec_settings.h"
@ -28,6 +29,9 @@ namespace webrtc {
namespace test {
namespace {
using ::testing::NotNull;
const VideoEncoder::Capabilities kCapabilities(false);
int32_t InitEncoder(VideoCodecType codec_type, VideoEncoder* encoder) {
@ -42,14 +46,11 @@ int32_t InitEncoder(VideoCodecType codec_type, VideoEncoder* encoder) {
1200 /* max_payload_size */));
}
int32_t InitDecoder(VideoCodecType codec_type, VideoDecoder* decoder) {
VideoCodec codec;
CodecSettings(codec_type, &codec);
codec.width = 640;
codec.height = 480;
codec.maxFramerate = 30;
RTC_CHECK(decoder);
return decoder->InitDecode(&codec, 1 /* number_of_cores */);
VideoDecoder::Settings DecoderSettings(VideoCodecType codec_type) {
VideoDecoder::Settings settings;
settings.set_max_render_resolution({640, 480});
settings.set_codec_type(codec_type);
return settings;
}
} // namespace
@ -126,7 +127,8 @@ TEST_P(VideoEncoderDecoderInstantiationTest, DISABLED_InstantiateVp8Codecs) {
for (int i = 0; i < num_decoders_; ++i) {
std::unique_ptr<VideoDecoder> decoder =
decoder_factory_->CreateVideoDecoder(vp8_format_);
EXPECT_EQ(0, InitDecoder(kVideoCodecVP8, decoder.get()));
ASSERT_THAT(decoder, NotNull());
EXPECT_TRUE(decoder->Configure(DecoderSettings(kVideoCodecVP8)));
decoders_.emplace_back(std::move(decoder));
}
}
@ -143,8 +145,9 @@ TEST_P(VideoEncoderDecoderInstantiationTest,
for (int i = 0; i < num_decoders_; ++i) {
std::unique_ptr<VideoDecoder> decoder =
decoder_factory_->CreateVideoDecoder(h264cbp_format_);
EXPECT_EQ(0, InitDecoder(kVideoCodecH264, decoder.get()));
decoders_.emplace_back(std::move(decoder));
ASSERT_THAT(decoder, NotNull());
EXPECT_TRUE(decoder->Configure(DecoderSettings(kVideoCodecH264)));
decoders_.push_back(std::move(decoder));
}
}

View File

@ -138,10 +138,9 @@ LibvpxVp8Decoder::~LibvpxVp8Decoder() {
Release();
}
int LibvpxVp8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
int ret_val = Release();
if (ret_val < 0) {
return ret_val;
bool LibvpxVp8Decoder::Configure(const Settings& settings) {
if (Release() < 0) {
return false;
}
if (decoder_ == NULL) {
decoder_ = new vpx_codec_ctx_t;
@ -157,7 +156,7 @@ int LibvpxVp8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
if (vpx_codec_dec_init(decoder_, vpx_codec_vp8_dx(), &cfg, flags)) {
delete decoder_;
decoder_ = nullptr;
return WEBRTC_VIDEO_CODEC_MEMORY;
return false;
}
propagation_cnt_ = -1;
@ -165,12 +164,12 @@ int LibvpxVp8Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
// Always start with a complete key frame.
key_frame_required_ = true;
if (inst && inst->buffer_pool_size) {
if (!buffer_pool_.Resize(*inst->buffer_pool_size)) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
if (absl::optional<int> buffer_pool_size = settings.buffer_pool_size()) {
if (!buffer_pool_.Resize(*buffer_pool_size)) {
return false;
}
}
return WEBRTC_VIDEO_CODEC_OK;
return true;
}
int LibvpxVp8Decoder::Decode(const EncodedImage& input_image,

View File

@ -29,8 +29,7 @@ class LibvpxVp8Decoder : public VideoDecoder {
LibvpxVp8Decoder();
~LibvpxVp8Decoder() override;
int InitDecode(const VideoCodec* inst, int number_of_cores) override;
bool Configure(const Settings& settings) override;
int Decode(const EncodedImage& input_image,
bool missing_frames,
int64_t /*render_time_ms*/) override;

View File

@ -244,10 +244,9 @@ TEST_F(TestVp8Impl, EncodeI420FrameAfterNv12Frame) {
encoder_->Encode(NextInputFrame(), nullptr));
}
TEST_F(TestVp8Impl, InitDecode) {
TEST_F(TestVp8Impl, Configure) {
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder_->Release());
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
decoder_->InitDecode(&codec_settings_, kNumCores));
EXPECT_TRUE(decoder_->Configure({}));
}
TEST_F(TestVp8Impl, OnEncodedImageReportsInfo) {

View File

@ -120,10 +120,9 @@ LibvpxVp9Decoder::~LibvpxVp9Decoder() {
}
}
int LibvpxVp9Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
int ret_val = Release();
if (ret_val < 0) {
return ret_val;
bool LibvpxVp9Decoder::Configure(const Settings& settings) {
if (Release() < 0) {
return false;
}
if (decoder_ == nullptr) {
@ -140,9 +139,9 @@ int LibvpxVp9Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
// - Make peak CPU usage under control (not depending on input)
cfg.threads = 1;
#else
if (!inst) {
// No config provided - don't know resolution to decode yet.
// Set thread count to one in the meantime.
const RenderResolution& resolution = settings.max_render_resolution();
if (!resolution.Valid()) {
// Postpone configuring number of threads until resolution is known.
cfg.threads = 1;
} else {
// We want to use multithreading when decoding high resolution videos. But
@ -156,31 +155,30 @@ int LibvpxVp9Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
// 4 for 1080p
// 8 for 1440p
// 18 for 4K
int num_threads =
std::max(1, 2 * (inst->width * inst->height) / (1280 * 720));
cfg.threads = std::min(number_of_cores, num_threads);
current_codec_ = *inst;
int num_threads = std::max(
1, 2 * resolution.Width() * resolution.Height() / (1280 * 720));
cfg.threads = std::min(settings.number_of_cores(), num_threads);
}
#endif
num_cores_ = number_of_cores;
current_settings_ = settings;
vpx_codec_flags_t flags = 0;
if (vpx_codec_dec_init(decoder_, vpx_codec_vp9_dx(), &cfg, flags)) {
return WEBRTC_VIDEO_CODEC_MEMORY;
return false;
}
if (!libvpx_buffer_pool_.InitializeVpxUsePool(decoder_)) {
return WEBRTC_VIDEO_CODEC_MEMORY;
return false;
}
inited_ = true;
// Always start with a complete key frame.
key_frame_required_ = true;
if (inst && inst->buffer_pool_size) {
if (!libvpx_buffer_pool_.Resize(*inst->buffer_pool_size) ||
!output_buffer_pool_.Resize(*inst->buffer_pool_size)) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
if (absl::optional<int> buffer_pool_size = settings.buffer_pool_size()) {
if (!libvpx_buffer_pool_.Resize(*buffer_pool_size) ||
!output_buffer_pool_.Resize(*buffer_pool_size)) {
return false;
}
}
@ -189,10 +187,10 @@ int LibvpxVp9Decoder::InitDecode(const VideoCodec* inst, int number_of_cores) {
if (status != VPX_CODEC_OK) {
RTC_LOG(LS_ERROR) << "Failed to enable VP9D_SET_LOOP_FILTER_OPT. "
<< vpx_codec_error(decoder_);
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
return false;
}
return WEBRTC_VIDEO_CODEC_OK;
return true;
}
int LibvpxVp9Decoder::Decode(const EncodedImage& input_image,
@ -209,17 +207,16 @@ int LibvpxVp9Decoder::Decode(const EncodedImage& input_image,
absl::optional<vp9::FrameInfo> frame_info =
vp9::ParseIntraFrameInfo(input_image.data(), input_image.size());
if (frame_info) {
if (frame_info->frame_width != current_codec_.width ||
frame_info->frame_height != current_codec_.height) {
RenderResolution frame_resolution(frame_info->frame_width,
frame_info->frame_height);
if (frame_resolution != current_settings_.max_render_resolution()) {
// Resolution has changed, tear down and re-init a new decoder in
// order to get correct sizing.
Release();
current_codec_.width = frame_info->frame_width;
current_codec_.height = frame_info->frame_height;
int reinit_status = InitDecode(&current_codec_, num_cores_);
if (reinit_status != WEBRTC_VIDEO_CODEC_OK) {
current_settings_.set_max_render_resolution(frame_resolution);
if (!Configure(current_settings_)) {
RTC_LOG(LS_WARNING) << "Failed to re-init decoder.";
return reinit_status;
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
}
} else {

View File

@ -30,7 +30,7 @@ class LibvpxVp9Decoder : public VP9Decoder {
virtual ~LibvpxVp9Decoder();
int InitDecode(const VideoCodec* inst, int number_of_cores) override;
bool Configure(const Settings& settings) override;
int Decode(const EncodedImage& input_image,
bool missing_frames,
@ -57,8 +57,7 @@ class LibvpxVp9Decoder : public VP9Decoder {
bool inited_;
vpx_codec_ctx_t* decoder_;
bool key_frame_required_;
VideoCodec current_codec_;
int num_cores_;
Settings current_settings_;
// Decoder should produce this format if possible.
const VideoFrameBuffer::Type preferred_output_format_;

View File

@ -2168,11 +2168,10 @@ TEST_F(TestVp9Impl, ReenablingUpperLayerAfterKFWithInterlayerPredIsEnabled) {
EXPECT_EQ(encoded_frames[0]._frameType, VideoFrameType::kVideoFrameDelta);
}
TEST_F(TestVp9Impl, HandlesEmptyInitDecode) {
TEST_F(TestVp9Impl, HandlesEmptyDecoderConfigure) {
std::unique_ptr<VideoDecoder> decoder = CreateDecoder();
// Check that nullptr settings are ok for decoder.
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
decoder->InitDecode(/*codec_settings=*/nullptr, 1));
// Check that default settings are ok for decoder.
EXPECT_TRUE(decoder->Configure({}));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, decoder->Release());
}