Commit a9ee55ac authored by Will Cassella's avatar Will Cassella Committed by Commit Bot

Modify DecoderPriorityCB so that it's called per-decoder

Currently, `DecoderSelector::decoder_priority_cb_` is called once
per-config, and can only return whether platform decoders specifically
should be prioritized, deprioritized, or left as-is.

This is somewhat inflexible, as it disallows skipping or deprioritizing
individual decoders based on other characteristics. This CL modifies
the decoder selector so that it runs the given predicate/callback once
per decoder, and modifies `DecoderPriority` to be one of
`kDeprioritized`, `kSkipped`, or `kNormal`. kNormal was chosen instead
of `kPrioritized` since it better reflects the mechanism of what's
happening. It's not being prioritized, it's just being left as-is in the
queue.

Change-Id: I9dfcecec5454201501dd1d09c23638da634fe188
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2388269Reviewed-by: default avatarFrank Liberato <liberato@chromium.org>
Commit-Queue: Will Cassella <cassew@google.com>
Cr-Commit-Position: refs/heads/master@{#805994}
parent a9b3e907
...@@ -243,6 +243,19 @@ VideoDecoderConfig TestVideoConfig::ExtraLargeEncrypted(VideoCodec codec) { ...@@ -243,6 +243,19 @@ VideoDecoderConfig TestVideoConfig::ExtraLargeEncrypted(VideoCodec codec) {
VIDEO_ROTATION_0, kExtraLargeSize, true); VIDEO_ROTATION_0, kExtraLargeSize, true);
} }
// static
VideoDecoderConfig TestVideoConfig::Custom(gfx::Size size, VideoCodec codec) {
return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
VIDEO_ROTATION_0, size, false);
}
// static
VideoDecoderConfig TestVideoConfig::CustomEncrypted(gfx::Size size,
VideoCodec codec) {
return GetTestConfig(codec, MinProfile(codec), VideoColorSpace::JPEG(),
VIDEO_ROTATION_0, size, true);
}
// static // static
gfx::Size TestVideoConfig::NormalCodedSize() { gfx::Size TestVideoConfig::NormalCodedSize() {
return kNormalSize; return kNormalSize;
......
...@@ -110,6 +110,11 @@ class TestVideoConfig { ...@@ -110,6 +110,11 @@ class TestVideoConfig {
static VideoDecoderConfig ExtraLarge(VideoCodec codec = kCodecVP8); static VideoDecoderConfig ExtraLarge(VideoCodec codec = kCodecVP8);
static VideoDecoderConfig ExtraLargeEncrypted(VideoCodec codec = kCodecVP8); static VideoDecoderConfig ExtraLargeEncrypted(VideoCodec codec = kCodecVP8);
static VideoDecoderConfig Custom(gfx::Size size,
VideoCodec codec = kCodecVP8);
static VideoDecoderConfig CustomEncrypted(gfx::Size size,
VideoCodec codec = kCodecVP8);
// Returns coded size for Normal and Large config. // Returns coded size for Normal and Large config.
static gfx::Size NormalCodedSize(); static gfx::Size NormalCodedSize();
static gfx::Size LargeCodedSize(); static gfx::Size LargeCodedSize();
......
...@@ -32,13 +32,14 @@ namespace { ...@@ -32,13 +32,14 @@ namespace {
const char kSelectDecoderTrace[] = "DecoderSelector::SelectDecoder"; const char kSelectDecoderTrace[] = "DecoderSelector::SelectDecoder";
template <typename T> template <typename ConfigT, typename DecoderT>
DecoderPriority UnspecifiedDecoderPriority(const T& /*config*/) { DecoderPriority NormalDecoderPriority(const ConfigT& /*config*/,
return DecoderPriority::kUnspecified; const DecoderT& /*decoder*/) {
return DecoderPriority::kNormal;
} }
DecoderPriority GetDefaultVideoDecoderPriority( DecoderPriority ResolutionBasedDecoderPriority(const VideoDecoderConfig& config,
const VideoDecoderConfig& config) { const VideoDecoder& decoder) {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
constexpr auto kSoftwareDecoderHeightCutoff = 360; constexpr auto kSoftwareDecoderHeightCutoff = 360;
#elif defined(OS_CHROMEOS) #elif defined(OS_CHROMEOS)
...@@ -47,25 +48,31 @@ DecoderPriority GetDefaultVideoDecoderPriority( ...@@ -47,25 +48,31 @@ DecoderPriority GetDefaultVideoDecoderPriority(
constexpr auto kSoftwareDecoderHeightCutoff = 720; constexpr auto kSoftwareDecoderHeightCutoff = 720;
#endif #endif
// We only do a height check to err on the side of hardware decoding // We only do a height check to err on the side of prioritizing platform
return config.visible_rect().height() < kSoftwareDecoderHeightCutoff // decoders.
? DecoderPriority::kPreferSoftwareDecoders const auto at_or_above_software_cutoff =
: DecoderPriority::kPreferPlatformDecoders; config.visible_rect().height() >= kSoftwareDecoderHeightCutoff;
// Platform decoders are deprioritized below the cutoff, and non-platform
// decoders are deprioritized above it.
return at_or_above_software_cutoff == decoder.IsPlatformDecoder()
? DecoderPriority::kNormal
: DecoderPriority::kDeprioritized;
} }
void SetDefaultDecoderPriorityCB(VideoDecoderSelector::DecoderPriorityCB* out) { void SetDefaultDecoderPriorityCB(VideoDecoderSelector::DecoderPriorityCB* out) {
if (base::FeatureList::IsEnabled(kResolutionBasedDecoderPriority)) { if (base::FeatureList::IsEnabled(kResolutionBasedDecoderPriority)) {
*out = base::BindRepeating(GetDefaultVideoDecoderPriority); *out = base::BindRepeating(ResolutionBasedDecoderPriority);
} else { } else {
*out = base::BindRepeating<DecoderPriority(const VideoDecoderConfig&)>( *out = base::BindRepeating(
UnspecifiedDecoderPriority); NormalDecoderPriority<VideoDecoderConfig, VideoDecoder>);
} }
} }
void SetDefaultDecoderPriorityCB(AudioDecoderSelector::DecoderPriorityCB* out) { void SetDefaultDecoderPriorityCB(AudioDecoderSelector::DecoderPriorityCB* out) {
// Platform audio decoders are not currently prioritized or deprioritized // Platform audio decoders are not currently prioritized or deprioritized
*out = base::BindRepeating<DecoderPriority(const AudioDecoderConfig&)>( *out = base::BindRepeating(
UnspecifiedDecoderPriority); NormalDecoderPriority<AudioDecoderConfig, AudioDecoder>);
} }
} // namespace } // namespace
...@@ -346,31 +353,31 @@ void DecoderSelector<StreamType>::RunSelectDecoderCB() { ...@@ -346,31 +353,31 @@ void DecoderSelector<StreamType>::RunSelectDecoderCB() {
template <DemuxerStream::Type StreamType> template <DemuxerStream::Type StreamType>
void DecoderSelector<StreamType>::FilterAndSortAvailableDecoders() { void DecoderSelector<StreamType>::FilterAndSortAvailableDecoders() {
// Filter out any decoders that do not support decryption std::vector<std::unique_ptr<Decoder>> decoders = std::move(decoders_);
if (config_.is_encrypted()) { std::vector<std::unique_ptr<Decoder>> deprioritized_decoders;
auto const non_decrypting = std::remove_if(
decoders_.begin(), decoders_.end(), for (auto& decoder : decoders) {
[](auto& decoder) { return !decoder->SupportsDecryption(); }); // Skip the decoder if this decoder doesn't support encryption for a
decoders_.erase(non_decrypting, decoders_.end()); // decrypting config
if (config_.is_encrypted() && !decoder->SupportsDecryption())
continue;
// Run the predicate on this decoder.
switch (decoder_priority_cb_.Run(config_, *decoder)) {
case DecoderPriority::kSkipped:
continue;
case DecoderPriority::kNormal:
decoders_.push_back(std::move(decoder));
break;
case DecoderPriority::kDeprioritized:
deprioritized_decoders.push_back(std::move(decoder));
break;
}
} }
// If platform decoders are prioritized for this config, shift all platform // Post-insert deprioritized decoders
// decoders to the front of the list (retaining their relative order). std::move(deprioritized_decoders.begin(), deprioritized_decoders.end(),
const auto decoder_priority = decoder_priority_cb_.Run(config_); std::inserter(decoders_, decoders_.end()));
switch (decoder_priority) {
case DecoderPriority::kUnspecified:
break;
case DecoderPriority::kPreferPlatformDecoders:
case DecoderPriority::kPreferSoftwareDecoders: {
auto prefer_platform_decoder =
decoder_priority == DecoderPriority::kPreferPlatformDecoders;
std::stable_partition(decoders_.begin(), decoders_.end(),
[prefer_platform_decoder](auto& decoder) {
return decoder->IsPlatformDecoder() ==
prefer_platform_decoder;
});
} break;
}
} }
// These forward declarations tell the compiler that we will use // These forward declarations tell the compiler that we will use
......
...@@ -28,10 +28,19 @@ class CdmContext; ...@@ -28,10 +28,19 @@ class CdmContext;
class DecryptingDemuxerStream; class DecryptingDemuxerStream;
class MediaLog; class MediaLog;
// Enum returned by `DecoderSelector::DecoderPriorityCB` to indicate
// priority of the current decoder.
enum class DecoderPriority { enum class DecoderPriority {
kUnspecified, // `kNormal` indicates that the current decoder should continue through with
kPreferPlatformDecoders, // selection in it's current order.
kPreferSoftwareDecoders, kNormal,
// `kDeprioritized` indicates that the current decoder should only be selected
// if other decoders have failed.
kDeprioritized,
// `kSkipped` indicates that the current decoder should not be used at all.
kSkipped,
}; };
// DecoderSelector handles construction and initialization of Decoders for a // DecoderSelector handles construction and initialization of Decoders for a
...@@ -51,10 +60,11 @@ class MEDIA_EXPORT DecoderSelector { ...@@ -51,10 +60,11 @@ class MEDIA_EXPORT DecoderSelector {
using CreateDecodersCB = using CreateDecodersCB =
base::RepeatingCallback<std::vector<std::unique_ptr<Decoder>>()>; base::RepeatingCallback<std::vector<std::unique_ptr<Decoder>>()>;
// Evaluates what type of decoders should be prioritized for the given config. // Prediate to evaluate whether a decoder should be prioritized,
// If |kUnspecified| is returned, nothing is prioritized. // deprioritized, or skipped.
using DecoderPriorityCB = using DecoderPriorityCB =
base::RepeatingCallback<DecoderPriority(const DecoderConfig&)>; base::RepeatingCallback<DecoderPriority(const DecoderConfig&,
const Decoder&)>;
// Emits the result of a single call to SelectDecoder(). Parameters are // Emits the result of a single call to SelectDecoder(). Parameters are
// 1: The initialized Decoder. nullptr if selection failed. // 1: The initialized Decoder. nullptr if selection failed.
......
...@@ -11,9 +11,11 @@ ...@@ -11,9 +11,11 @@
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/test/gmock_callback_support.h" #include "base/test/gmock_callback_support.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "media/base/demuxer_stream.h" #include "media/base/demuxer_stream.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h" #include "media/base/media_util.h"
#include "media/base/mock_filters.h" #include "media/base/mock_filters.h"
#include "media/base/test_helpers.h" #include "media/base/test_helpers.h"
...@@ -106,15 +108,23 @@ class AudioDecoderSelectorTestParam { ...@@ -106,15 +108,23 @@ class AudioDecoderSelectorTestParam {
} }
static media::DecoderPriority MockDecoderPriorityCB( static media::DecoderPriority MockDecoderPriorityCB(
const media::AudioDecoderConfig& config) { const media::AudioDecoderConfig& config,
return config.samples_per_second() > const media::AudioDecoder& decoder) {
TestAudioConfig::NormalSampleRateValue() const auto above_cutoff =
? media::DecoderPriority::kPreferPlatformDecoders config.samples_per_second() > TestAudioConfig::NormalSampleRateValue();
: media::DecoderPriority::kPreferSoftwareDecoders; return above_cutoff == decoder.IsPlatformDecoder()
? media::DecoderPriority::kNormal
: media::DecoderPriority::kDeprioritized;
} }
static media::DecoderPriority UnspecifiedDecoderPriorityCB( static media::DecoderPriority NormalDecoderPriorityCB(
const media::AudioDecoderConfig& /*config*/) { const media::AudioDecoderConfig& /*config*/,
return media::DecoderPriority::kUnspecified; const media::AudioDecoder& /*decoder*/) {
return media::DecoderPriority::kNormal;
}
static media::DecoderPriority SkipDecoderPriorityCB(
const media::AudioDecoderConfig& /*config*/,
const media::AudioDecoder& /*decoder*/) {
return media::DecoderPriority::kSkipped;
} }
static void UseNormalClearDecoderConfig( static void UseNormalClearDecoderConfig(
...@@ -177,15 +187,23 @@ class VideoDecoderSelectorTestParam { ...@@ -177,15 +187,23 @@ class VideoDecoderSelectorTestParam {
} }
static media::DecoderPriority MockDecoderPriorityCB( static media::DecoderPriority MockDecoderPriorityCB(
const media::VideoDecoderConfig& config) { const media::VideoDecoderConfig& config,
return config.visible_rect().height() > const media::VideoDecoder& decoder) {
TestVideoConfig::NormalCodedSize().height() auto const above_cutoff = config.visible_rect().height() >
? media::DecoderPriority::kPreferPlatformDecoders TestVideoConfig::NormalCodedSize().height();
: media::DecoderPriority::kPreferSoftwareDecoders; return decoder.IsPlatformDecoder() == above_cutoff
? media::DecoderPriority::kNormal
: media::DecoderPriority::kDeprioritized;
}
static media::DecoderPriority NormalDecoderPriorityCB(
const media::VideoDecoderConfig& /*config*/,
const media::VideoDecoder& /*decoder*/) {
return media::DecoderPriority::kNormal;
} }
static media::DecoderPriority UnspecifiedDecoderPriorityCB( static media::DecoderPriority SkipDecoderPriorityCB(
const media::VideoDecoderConfig& /*config*/) { const media::VideoDecoderConfig& /*config*/,
return media::DecoderPriority::kUnspecified; const media::VideoDecoder& /*decoder*/) {
return media::DecoderPriority::kSkipped;
} }
static void UseNormalClearDecoderConfig( static void UseNormalClearDecoderConfig(
...@@ -374,8 +392,6 @@ class DecoderSelectorTest : public ::testing::Test { ...@@ -374,8 +392,6 @@ class DecoderSelectorTest : public ::testing::Test {
task_environment_.GetMainThreadTaskRunner(), task_environment_.GetMainThreadTaskRunner(),
base::BindRepeating(&Self::CreateDecoders, base::Unretained(this)), base::BindRepeating(&Self::CreateDecoders, base::Unretained(this)),
&media_log_); &media_log_);
decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::MockDecoderPriorityCB));
decoder_selector_->Initialize( decoder_selector_->Initialize(
traits_.get(), &demuxer_stream_, cdm_context_.get(), traits_.get(), &demuxer_stream_, cdm_context_.get(),
base::BindRepeating(&Self::OnWaiting, base::Unretained(this))); base::BindRepeating(&Self::OnWaiting, base::Unretained(this)));
...@@ -420,6 +436,9 @@ class DecoderSelectorTest : public ::testing::Test { ...@@ -420,6 +436,9 @@ class DecoderSelectorTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(DecoderSelectorTest); DISALLOW_COPY_AND_ASSIGN(DecoderSelectorTest);
}; };
using VideoDecoderSelectorTest =
DecoderSelectorTest<VideoDecoderSelectorTestParam>;
using DecoderSelectorTestParams = using DecoderSelectorTestParams =
::testing::Types<AudioDecoderSelectorTestParam, ::testing::Types<AudioDecoderSelectorTestParam,
VideoDecoderSelectorTestParam>; VideoDecoderSelectorTestParam>;
...@@ -505,6 +524,8 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_PrioritizePlatformDecoders) { ...@@ -505,6 +524,8 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_PrioritizePlatformDecoders) {
this->UseHighQualityClearDecoderConfig(); this->UseHighQualityClearDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::MockDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -529,6 +550,8 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_DeprioritizePlatformDecoders) { ...@@ -529,6 +550,8 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_DeprioritizePlatformDecoders) {
this->UseClearDecoderConfig(); this->UseClearDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::MockDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -544,9 +567,9 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_DeprioritizePlatformDecoders) { ...@@ -544,9 +567,9 @@ TYPED_TEST(DecoderSelectorTest, ClearStream_DeprioritizePlatformDecoders) {
} }
// Tests that platform and non-platform decoders remain in the order they are // Tests that platform and non-platform decoders remain in the order they are
// given for a priority callback returning 'kNop'. // given for a priority callback returning 'kNormal'.
TYPED_TEST(DecoderSelectorTest, TYPED_TEST(DecoderSelectorTest,
ClearStream_NopPriorityCallbackRetainsGivenOrder) { ClearStream_NormalPriorityCallbackRetainsGivenOrder) {
this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed); this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed);
this->AddMockDecoder(kDecoder2, kAlwaysSucceed); this->AddMockDecoder(kDecoder2, kAlwaysSucceed);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed); this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
...@@ -555,7 +578,7 @@ TYPED_TEST(DecoderSelectorTest, ...@@ -555,7 +578,7 @@ TYPED_TEST(DecoderSelectorTest,
this->UseClearDecoderConfig(); this->UseClearDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting( this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::UnspecifiedDecoderPriorityCB)); base::BindRepeating(TypeParam::NormalDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -570,6 +593,77 @@ TYPED_TEST(DecoderSelectorTest, ...@@ -570,6 +593,77 @@ TYPED_TEST(DecoderSelectorTest,
this->SelectDecoder(); this->SelectDecoder();
} }
TYPED_TEST(DecoderSelectorTest, ClearStream_SkipAllDecoders) {
this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed);
this->AddMockDecoder(kDecoder2, kAlwaysSucceed);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
this->UseClearDecoderConfig();
this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::SkipDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
// Tests the production predicate for `DecoderSelector<DemuxerStream::VIDEO>`
TEST_F(VideoDecoderSelectorTest, ClearStream_PrioritizeSoftwareDecoders) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(kResolutionBasedDecoderPriority);
this->AddMockPlatformDecoder(kDecoder1, kClearOnly);
this->AddMockDecoder(kDecoder2, kClearOnly);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
// Create a clear config that will cause software decoders to be
// prioritized on any platform.
this->demuxer_stream_.set_video_decoder_config(
TestVideoConfig::Custom(gfx::Size(64, 64)));
this->CreateDecoderSelector();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder4, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder3, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
// Tests the production predicate for `DecoderSelector<DemuxerStream::VIDEO>`
TEST_F(VideoDecoderSelectorTest, ClearStream_PrioritizePlatformDecoders) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(kResolutionBasedDecoderPriority);
this->AddMockPlatformDecoder(kDecoder1, kClearOnly);
this->AddMockDecoder(kDecoder2, kClearOnly);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
// Create a clear config that will cause hardware decoders to be prioritized
// on any platform.
this->demuxer_stream_.set_video_decoder_config(
TestVideoConfig::Custom(gfx::Size(4096, 4096)));
this->CreateDecoderSelector();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder3, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder4, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
// Tests for encrypted streams. // Tests for encrypted streams.
// Tests that non-decrypting decoders are filtered out by DecoderSelector // Tests that non-decrypting decoders are filtered out by DecoderSelector
...@@ -604,6 +698,8 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_PrioritizePlatformDecoders) { ...@@ -604,6 +698,8 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_PrioritizePlatformDecoders) {
this->UseHighQualityEncryptedDecoderConfig(); this->UseHighQualityEncryptedDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::MockDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -628,6 +724,8 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_DeprioritizePlatformDecoders) { ...@@ -628,6 +724,8 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_DeprioritizePlatformDecoders) {
this->UseEncryptedDecoderConfig(); this->UseEncryptedDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::MockDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder2, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -643,9 +741,9 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_DeprioritizePlatformDecoders) { ...@@ -643,9 +741,9 @@ TYPED_TEST(DecoderSelectorTest, EncryptedStream_DeprioritizePlatformDecoders) {
} }
// Tests that platform and non-platform decoders remain in the order they are // Tests that platform and non-platform decoders remain in the order they are
// given for a priority callback returning 'kNop'. // given for a priority callback returning 'kNormal'.
TYPED_TEST(DecoderSelectorTest, TYPED_TEST(DecoderSelectorTest,
EncryptedStream_NopPriorityCallbackRetainsGivenOrder) { EncryptedStream_NormalPriorityCallbackRetainsGivenOrder) {
this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed); this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed);
this->AddMockDecoder(kDecoder2, kAlwaysSucceed); this->AddMockDecoder(kDecoder2, kAlwaysSucceed);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed); this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
...@@ -654,7 +752,7 @@ TYPED_TEST(DecoderSelectorTest, ...@@ -654,7 +752,7 @@ TYPED_TEST(DecoderSelectorTest,
this->UseEncryptedDecoderConfig(); this->UseEncryptedDecoderConfig();
this->CreateDecoderSelector(); this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting( this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::UnspecifiedDecoderPriorityCB)); base::BindRepeating(TypeParam::NormalDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull())); EXPECT_CALL(*this, OnDecoderSelected(kDecoder1, IsNull()));
this->SelectDecoder(); this->SelectDecoder();
...@@ -669,6 +767,21 @@ TYPED_TEST(DecoderSelectorTest, ...@@ -669,6 +767,21 @@ TYPED_TEST(DecoderSelectorTest,
this->SelectDecoder(); this->SelectDecoder();
} }
TYPED_TEST(DecoderSelectorTest, EncryptedStream_SkipAllDecoders) {
this->AddMockPlatformDecoder(kDecoder1, kAlwaysSucceed);
this->AddMockDecoder(kDecoder2, kAlwaysSucceed);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
this->UseEncryptedDecoderConfig();
this->CreateDecoderSelector();
this->decoder_selector_->OverrideDecoderPriorityCBForTesting(
base::BindRepeating(TypeParam::SkipDecoderPriorityCB));
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
TYPED_TEST(DecoderSelectorTest, EncryptedStream_NoDecryptor_OneClearDecoder) { TYPED_TEST(DecoderSelectorTest, EncryptedStream_NoDecryptor_OneClearDecoder) {
this->AddMockDecoder(kDecoder1, kClearOnly); this->AddMockDecoder(kDecoder1, kClearOnly);
this->CreateCdmContext(kNoDecryptor); this->CreateCdmContext(kNoDecryptor);
...@@ -842,4 +955,52 @@ TYPED_TEST(DecoderSelectorTest, ClearToEncryptedStream_DecryptOnly) { ...@@ -842,4 +955,52 @@ TYPED_TEST(DecoderSelectorTest, ClearToEncryptedStream_DecryptOnly) {
this->SelectDecoder(); this->SelectDecoder();
} }
// Tests the production predicate for `DecoderSelector<DemuxerStream::VIDEO>`
TEST_F(VideoDecoderSelectorTest, EncryptedStream_PrioritizeSoftwareDecoders) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(kResolutionBasedDecoderPriority);
this->AddMockPlatformDecoder(kDecoder1, kClearOnly);
this->AddMockDecoder(kDecoder2, kClearOnly);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
// Create an encrypted config that will cause software decoders to be
// prioritized on any platform.
this->demuxer_stream_.set_video_decoder_config(
TestVideoConfig::CustomEncrypted(gfx::Size(64, 64)));
this->CreateDecoderSelector();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder4, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder3, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
// Tests the production predicate for `DecoderSelector<DemuxerStream::VIDEO>`
TEST_F(VideoDecoderSelectorTest, EncryptedStream_PrioritizePlatformDecoders) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(kResolutionBasedDecoderPriority);
this->AddMockPlatformDecoder(kDecoder1, kClearOnly);
this->AddMockDecoder(kDecoder2, kClearOnly);
this->AddMockPlatformDecoder(kDecoder3, kAlwaysSucceed);
this->AddMockDecoder(kDecoder4, kAlwaysSucceed);
// Create an encrypted config that will cause hardware decoders to be
// prioritized on any platform.
this->demuxer_stream_.set_video_decoder_config(
TestVideoConfig::CustomEncrypted(gfx::Size(4096, 4096)));
this->CreateDecoderSelector();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder3, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kDecoder4, IsNull()));
this->SelectDecoder();
EXPECT_CALL(*this, OnDecoderSelected(kNoDecoder, IsNull()));
this->SelectDecoder();
}
} // namespace media } // namespace media
...@@ -51,11 +51,13 @@ static std::string GetDecoderName(int i) { ...@@ -51,11 +51,13 @@ static std::string GetDecoderName(int i) {
return std::string("VideoDecoder") + base::NumberToString(i); return std::string("VideoDecoder") + base::NumberToString(i);
} }
DecoderPriority MockDecoderPriority(const VideoDecoderConfig& config) { DecoderPriority MockDecoderPriority(const VideoDecoderConfig& config,
return config.visible_rect().height() >= const VideoDecoder& decoder) {
TestVideoConfig::LargeCodedSize().height() auto const at_or_above_cutoff = config.visible_rect().height() >=
? DecoderPriority::kPreferPlatformDecoders TestVideoConfig::LargeCodedSize().height();
: DecoderPriority::kPreferSoftwareDecoders; return at_or_above_cutoff == decoder.IsPlatformDecoder()
? DecoderPriority::kNormal
: DecoderPriority::kDeprioritized;
} }
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment