switch (decoder_state_) {
case DecoderState::kCreated:
+ case DecoderState::kReleasedBeforeInit:
TIZEN_MEDIA_LOG(ERROR)
<< "Reset does nothing in state " << decoder_state_;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
case DecoderState::kCreated:
case DecoderState::kError:
case DecoderState::kResetting:
+ case DecoderState::kReleasedBeforeInit:
TIZEN_MEDIA_LOG(ERROR)
<< "Invalid call to decode in state: " << decoder_state_;
decoder_state_ = DecoderState::kError;
VideoDecoder::InitCB init_cb,
VideoDecoder::OutputCB output_cb,
WaitingCB waiting_cb) {
- if (decoder_state_ == DecoderState::kResourceTaken ||
- decoder_state_ == DecoderState::kSuspended) {
+ initialized_ = true;
+ waiting_for_key_ = false;
+ first_frame_done_ = false;
+
+ if (decoder_state_ == DecoderState::kReleasedBeforeInit) {
+ if (config.is_rtc()) {
+ // WebRTC decoding has it's own decoding pipeline allowing for SW decoding
+ // to be done seamlessly, without reloading whole player. That is why we
+ // can suspend decoder, still having software fallback and additionally
+ // we are still able to resume HW decoding when needed.
+ decoder_state_ = DecoderState::kSuspended;
+ } else {
+ // Behave like we would receive some internal error from HW decoder.
+ // It should trigger software fallback where possible or upper layer
+ // reinitialization if seamless decoder switch is not possible.
+ decoder_state_ = DecoderState::kResourceTaken;
+ }
+ }
+
+ if (decoder_state_ == DecoderState::kResourceTaken) {
std::move(init_cb).Run(DecoderStatus::Codes::kFailedToCreateDecoder);
return;
}
- waiting_for_key_ = false;
- first_frame_done_ = false;
+ if (decoder_state_ == DecoderState::kSuspended) {
+ std::move(init_cb).Run(DecoderStatus::Codes::kOk);
+ return;
+ }
if (decoder_state_ != DecoderState::kCreated) {
if (low_delay != low_delay_) {
void TTvdVideoDecoderImpl::ReleaseResources() {
TIZEN_MEDIA_LOG(INFO) << "Release decoder in state: " << decoder_state_;
+ if (!initialized_) {
+ // Current configuration is not yet known, so we need to used dedicated
+ // state to track this. Note that during |Initialize| it should change
+ // to either of below values.
+ decoder_state_ = DecoderState::kReleasedBeforeInit;
+ return;
+ }
+
if (config_.is_rtc()) {
// WebRTC decoding has it's own decoding pipeline allowing for SW decoding
// to be done seamlessly, without reloading whole player. That is why we
} else {
// Behave like we would receive some internal error from HW decoder.
// It should trigger software fallback where possible or upper layer
- // reinitialization is seamless decoder switch is not possible.
+ // reinitialization if seamless decoder switch is not possible.
decoder_state_ = DecoderState::kResourceTaken;
}
case DecoderState::kResourceTaken:
case DecoderState::kLazyInitializing:
case DecoderState::kSuspended:
+ case DecoderState::kReleasedBeforeInit:
TIZEN_MEDIA_LOG(ERROR)
<< "Facade error in unexpected state: " << decoder_state_;
return;
case TTvdVideoDecoderImpl::DecoderState::kSuspended:
o << "Suspended";
break;
+ case TTvdVideoDecoderImpl::DecoderState::kReleasedBeforeInit:
+ o << "ReleasedBeforeInit";
+ break;
}
return o;
}
#include "media/filters/tizen/ttvd_video_decoder.h"
#include "absl/types/optional.h"
+#include "base/test/task_environment.h"
#include "base/threading/thread.h"
+#include "base/tizen/global_resource_manager.h"
#include "base/tizen/provider_callbacks_helper.h"
#include "base/tizen/resource_manager.h"
+#include "media/base/test_helpers.h"
#include "media/filters/tizen/decoder_promotion.h"
#include "media/filters/tizen/media_video_codec.h"
#include "media/gpu/test/fake_command_buffer_helper.h"
gpu_thread.FlushForTesting();
}
+struct InitData {
+ bool is_rtc;
+ bool should_succeed;
+ std::vector<suspend_resume::State> operations;
+};
+
+constexpr const bool kRtc = true;
+constexpr const bool kNormal = false;
+constexpr const bool kInitSuccess = true;
+constexpr const bool kInitError = false;
+
+struct InitData kPartialViewTests[] = {
+ {kRtc, kInitSuccess, {suspend_resume::State::RESUMED}},
+ {kNormal, kInitSuccess, {suspend_resume::State::RESUMED}},
+ {kRtc, kInitSuccess, {suspend_resume::State::PARTIAL}},
+ {kNormal, kInitError, {suspend_resume::State::PARTIAL}},
+ {kRtc, kInitSuccess, {suspend_resume::State::SUSPENDED}},
+ {kNormal, kInitSuccess, {suspend_resume::State::SUSPENDED}},
+ {kRtc,
+ kInitSuccess,
+ {suspend_resume::State::PARTIAL, suspend_resume::State::RESUMED}},
+ {kNormal,
+ kInitSuccess,
+ {suspend_resume::State::PARTIAL, suspend_resume::State::RESUMED}},
+ {kRtc,
+ kInitSuccess,
+ {suspend_resume::State::PARTIAL, suspend_resume::State::SUSPENDED,
+ suspend_resume::State::PARTIAL}},
+ {kNormal,
+ kInitError,
+ {suspend_resume::State::PARTIAL, suspend_resume::State::SUSPENDED,
+ suspend_resume::State::PARTIAL}},
+};
+
+class TTvdVideoDecoderTestInitialize : public testing::TestWithParam<InitData> {
+};
+
+TEST_P(TTvdVideoDecoderTestInitialize, InitializePartialViewBeforeCreation) {
+ const auto init_data = GetParam();
+
+ FakeResourceManager fake_resource_manager;
+ SetGlobalResourceManagerForTesting(&fake_resource_manager);
+ DecoderPromotion* decoder_promotion = DecoderPromotion::GetInstance();
+ decoder_promotion->SetResourceManagerForTesting(&fake_resource_manager);
+
+ base::test::TaskEnvironment task_environment{
+ base::test::TaskEnvironment::MainThreadType::IO};
+
+ base::Thread gpu_thread("gpu_thread");
+ ASSERT_TRUE(gpu_thread.StartAndWaitForTesting());
+
+ gpu::GpuDriverBugWorkarounds gpu_workarounds;
+
+ for (auto state : init_data.operations) {
+ suspend_resume::NotifyStateChange(state);
+ }
+
+ TTvdVideoDecoder video_decoder(
+ base::BindRepeating(
+ [](scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ -> scoped_refptr<CommandBufferHelper> {
+ return base::MakeRefCounted<FakeCommandBufferHelper>(task_runner);
+ },
+ gpu_thread.task_runner()),
+ gpu_thread.task_runner(),
+ base::BindRepeating(
+ [](const gpu::GpuDriverBugWorkarounds*)
+ -> std::unique_ptr<DecoderFacadeVideo> { return nullptr; }),
+ gpu_workarounds);
+
+ VideoDecoderConfig config = TestVideoConfig::NormalH264();
+ if (init_data.is_rtc) {
+ config.set_is_rtc(true);
+ }
+ constexpr const bool kLowLatency = true;
+ CdmContext* kNullCdmContextLowLatency = nullptr;
+ video_decoder.Initialize(
+ config, kLowLatency, kNullCdmContextLowLatency,
+ base::BindOnce(
+ [](bool should_succeed, base::OnceClosure quit_closure,
+ DecoderStatus status) {
+ EXPECT_EQ(status.is_ok(), should_succeed)
+ << "Returned code: " << static_cast<int>(status.code());
+ std::move(quit_closure).Run();
+ },
+ init_data.should_succeed, task_environment.QuitClosure()),
+ base::DoNothing(), base::DoNothing());
+
+ task_environment.RunUntilQuit();
+ gpu_thread.FlushForTesting();
+}
+
+INSTANTIATE_TEST_SUITE_P(MultipleStartingStates,
+ TTvdVideoDecoderTestInitialize,
+ testing::ValuesIn(kPartialViewTests));
+
} // namespace media