[TTVD] Handle decoder reinit on resolution change 09/315409/2
authorJakub Gajownik <j.gajownik2@samsung.com>
Wed, 24 Jul 2024 10:55:25 +0000 (12:55 +0200)
committerBot Blink <blinkbot@samsung.com>
Wed, 31 Jul 2024 12:26:27 +0000 (12:26 +0000)
Adjusts the handling of the OMX decoder reinitialization scenario, which
happens during i.a. the MSE resolution change. Allows for reuse of the
same decoder, if the underlying resource manager category does not need
to change. This change does not fully implement the seamless resolution
change scenario (on the decoder side) because of 2 cases:

1) Due to the TTVD decoder currently not being able to decode multiple
frames ahead of time, there is a brief stutter during resolution
changes. This happens, because the decoder has to be flushed while
the renderer is already expecting presentable frames.

2) For similar reasons to pt.1, if the currently allocated decoder has
to be replaced by a different one, with a new category, the stutter will
be longer since now a whole new OMX instance has to be created.

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-372
Change-Id: I12de4a887a17ddc84c235887f369b316145bda4a
Signed-off-by: Jakub Gajownik <j.gajownik2@samsung.com>
media/filters/tizen/decoder_promotion.cc
media/filters/tizen/decoder_promotion.h
media/filters/tizen/omx/omx_facade_video.cc
media/filters/tizen/ttvd_video_decoder.cc
media/filters/tizen/ttvd_video_decoder_impl.cc
media/filters/tizen/ttvd_video_decoder_impl.h

index bc1df7983c40d1dd4641d81b6afafa91d4c1c409..11c615a1ff5ad9ae0e97bec93ae2e175d768197b 100644 (file)
@@ -505,6 +505,29 @@ absl::optional<AllocatedDecoder> DecoderPromotion::SelectDecoder(
   return absl::nullopt;
 }
 
+bool DecoderPromotion::NeedsDecoderReselection(
+    const AllocatedDecoder& current_decoder,
+    MediaVideoCodec codec,
+    VideoCodecLevel level,
+    gfx::Size coded_size,
+    VideoChromaSampling sampling,
+    size_t bit_depth,
+    LatencyMode latency,
+    const gpu::GpuDriverBugWorkarounds* workarounds) {
+  base::AutoLock auto_lock(lock_);
+  auto decoder_it = std::find_if(
+      video_decoders_.begin(), video_decoders_.end(),
+      [&current_decoder](const std::pair<int, Entry>& el) {
+        return el.second.component_name == current_decoder.component_name;
+      });
+  TIZEN_MEDIA_LOG_ASSERT(decoder_it != video_decoders_.end())
+      << "Decoder used for reselection has to be currently allocated";
+  auto new_category =
+      SelectVideoDecoderCategory(GetResourceManager(), codec, level, coded_size,
+                                 sampling, bit_depth, latency, workarounds);
+  return new_category != decoder_it->second.category;
+}
+
 absl::optional<AllocatedDecoder> DecoderPromotion::SelectAudioDecoder(
     AllocationCallbacks callbacks) {
   base::AutoLock auto_lock(lock_);
index 39bf8eeee16c78eb1f9bb445d4039b994f71a14e..78eac12e79130bde8d9335d028a096c15705fa8d 100644 (file)
@@ -104,6 +104,16 @@ class DecoderPromotion {
       AllocationCallbacks callbacks,
       const gpu::GpuDriverBugWorkarounds* workarounds = nullptr);
 
+  bool NeedsDecoderReselection(
+      const AllocatedDecoder& current_decoder,
+      MediaVideoCodec codec,
+      VideoCodecLevel level,
+      gfx::Size coded_size,
+      VideoChromaSampling sampling,
+      size_t bit_depth,
+      LatencyMode latency,
+      const gpu::GpuDriverBugWorkarounds* workarounds = nullptr);
+
   absl::optional<AllocatedDecoder> SelectAudioDecoder(
       AllocationCallbacks callbacks);
 
index 410abeea4862d06439c109994a70df185e4a7e9d..07b192b729cbb432f54641e755e9841f8cfa285b 100644 (file)
@@ -181,7 +181,7 @@ bool OmxFacadeVideo::InitializeComponent(const std::string& component_name,
     param.eVideoClipOpMode = OMX_VIDEO_CLIP_OP_MAX_HZ;
 #endif
   } else {
-    param.nVideoDecodingType = OMX_Video_Decoding_Normal;
+    param.nVideoDecodingType = OMX_Video_Decoding_Seamless;
 #if TIZEN_VERSION_AT_LEAST(7, 0, 0)
     param.eVideoClipOpMode = OMX_VIDEO_CLIP_OP_NORMAL;
 #endif
index d16c7da3d044140c16122effba88ab7dc269a52b..7c43d3ee8b8f8736f5d4440547876babab4c3e2b 100644 (file)
@@ -74,7 +74,8 @@ void TTvdVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                   InitCB init_cb,
                                   const OutputCB& output_cb,
                                   const WaitingCB& waiting_cb) {
-  TIZEN_MEDIA_LOG(INFO) << "Initialize TTvdVideoDecoder: "
+  TIZEN_MEDIA_LOG(INFO) << (decoder_impl_ ? "Reinitialize" : "Initialize")
+                        << " TTvdVideoDecoder: "
                         << config.AsHumanReadableString()
                         << ", low delay: " << low_delay
                         << ", cdm context: " << cdm_context;
index b89ad19f73afa397c7e82cf692b3a5068b2f50c7..a5a5d0f19b808423583985f9a2e6e3b2d69e092e 100644 (file)
@@ -649,12 +649,14 @@ void TTvdVideoDecoderImpl::Initialize(VideoDecoderConfig config,
     return;
   }
 
+  waiting_for_key_ = false;
+  first_frame_done_ = false;
+
   if (decoder_state_ != DecoderState::kCreated) {
-    if (!CleanFacade()) {
-      std::move(init_cb).Run(DecoderStatus::Codes::kFailedToCreateDecoder);
+    if (low_delay != low_delay_) {
+      std::move(init_cb).Run(DecoderStatus::Codes::kCantChangeCodec);
       return;
     }
-    allocated_decoder_.reset();
 
     ttvd_decoded_frame_pool_.clear();
     ranges_.Clear();
@@ -662,10 +664,14 @@ void TTvdVideoDecoderImpl::Initialize(VideoDecoderConfig config,
     decoding_results_.clear();
     last_processing_frame_ =
         std::make_pair(base::TimeDelta(), ProcessingAction::kRender);
-    waiting_for_key_ = false;
-    first_frame_done_ = false;
 
-    decoder_state_ = DecoderState::kCreated;
+    // Do not clean facade and allocated resource, as decoder is being
+    // reinitialized. It's possible that we can reuse same decoder after
+    // flushing, but this will be known after first frame is received.
+    decoder_state_ = DecoderState::kLazyInitializing;
+    decoder_facade_->Flush(
+        base::BindOnce(std::move(init_cb), DecoderStatus::Codes::kOk));
+    return;
   }
 
   CHECK_EQ(decoder_state_, DecoderState::kCreated)
@@ -992,17 +998,10 @@ bool TTvdVideoDecoderImpl::AllocateDecoder() {
   // Use picture size instead of |coded_size| as resource manager might
   // return that valid resolutions (e.g 3840x2176) are not supported on
   // several boards.
-  auto latency = [&]() {
-    if (IsForGameStreaming())
-      return LatencyMode::kGameMode;
-    if (config_.is_rtc())
-      return LatencyMode::kLow;
-    return LatencyMode::kNormal;
-  }();
   auto decoder = DecoderPromotion::GetInstance()->SelectDecoder(
       codec, config_.level(), config_.visible_rect().size(),
-      config_.chroma_sampling, config_.bit_depth, latency, std::move(callbacks),
-      &workarounds_);
+      config_.chroma_sampling, config_.bit_depth, GetLatencyMode(),
+      std::move(callbacks), &workarounds_);
   if (!decoder) {
     return false;
   }
@@ -1256,6 +1255,25 @@ void TTvdVideoDecoderImpl::InitializeInternal() {
       << "Wrong state: " << decoder_state_;
   TIZEN_MEDIA_LOG(VERBOSE) << "Initialize";
 
+  if (allocated_decoder_) {
+    // TODO(vdwasm): Figure out how to reinitialize the decoder in case
+    // the underlying resource needs to change. For now let's fail the reinit
+    // request, which will cause the |DecoderSelector| to just initialize a new
+    // OMX instance.
+    if (DecoderPromotion::GetInstance()->NeedsDecoderReselection(
+            *allocated_decoder_, VideoCodecToMediaVideoCodec(config_.codec()),
+            config_.level(), config_.coded_size(), config_.chroma_sampling,
+            config_.bit_depth, GetLatencyMode(), &workarounds_)) {
+      TIZEN_MEDIA_LOG(WARNING)
+          << "Can't reconfigure without reallocation, incoming config: "
+          << config_.AsHumanReadableString();
+      NotifyInitializationFailed();
+      return;
+    }
+    OnInitializationDone(true);
+    return;
+  }
+
   if (!AllocateDecoder()) {
     TIZEN_MEDIA_LOG(ERROR) << "Cannot allocate proper decoder";
     decoder_state_ = DecoderState::kError;
@@ -1885,6 +1903,14 @@ bool TTvdVideoDecoderImpl::ShouldTriggerLazyFrames() const {
           lazy_frames_in_syncing_);
 }
 
+LatencyMode TTvdVideoDecoderImpl::GetLatencyMode() const {
+  if (IsForGameStreaming())
+    return LatencyMode::kGameMode;
+  if (config_.is_rtc())
+    return LatencyMode::kLow;
+  return LatencyMode::kNormal;
+}
+
 void TTvdVideoDecoderImpl::RemoveDecoderDependentResults() {
   base::WaitableEvent event;
   if (!gpu_task_runner_->PostTask(
index d613c4cead4f109831f40b547b4cdffb7070fe4d..0461ec74c7833dcaeedb914d74f4024d0abe4370 100644 (file)
@@ -229,6 +229,8 @@ class MEDIA_EXPORT TTvdVideoDecoderImpl {
   bool ShouldDecodeForTexturing() const;
   bool ShouldTriggerLazyFrames() const;
 
+  LatencyMode GetLatencyMode() const;
+
   // Removes entries from |decoding_results_| that holds data owned
   // by platform video decoder. Should be used whenever we lose access
   // to decoder, e.g resource conflict, suspending, etc.