[M120 Migration][MM] Ensure player is destroyed before IEMEDrmBridge 99/308499/3
authorzhishun.zhou <zhishun.zhou@samsung.com>
Tue, 26 Mar 2024 09:04:50 +0000 (17:04 +0800)
committerBot Blink <blinkbot@samsung.com>
Wed, 27 Mar 2024 19:12:24 +0000 (19:12 +0000)
Issue:
when app use EME, chromium pass encrytped frame and key handle to MM,
and then MM decrypt frames.
When WebMediaPlayerImpl is destroyed, PipelineController::Stop will
destroy player by mojom IPC in browser process.
But IEMEDrmBridge is destroyed in render process.
If IEMEDrmBridge is destroyed before player, MM still use key handle to
decrypt, then it will crash.

Solution:
Use a sync IPC to ensure player is destroyed before IEMEDrmBridge

Patches from:
https://review.tizen.org/gerrit/#/c/299374/
https://review.tizen.org/gerrit/#/c/300392/
https://review.tizen.org/gerrit/#/c/302624/

Change-Id: I20b77e1c53d3dca685aaf0f355b3b8a149ccc056
Signed-off-by: wuxiaoliang <xliang.wu@samsung.com>
Signed-off-by: zhishun.zhou <zhishun.zhou@samsung.com>
21 files changed:
media/base/pipeline.h
media/base/pipeline_impl.cc
media/base/pipeline_impl.h
media/base/renderer.h
media/filters/pipeline_controller.cc
media/filters/pipeline_controller.h
media/mojo/clients/mojo_renderer.cc
media/mojo/clients/mojo_renderer.h
media/mojo/clients/mojo_renderer_wrapper.cc
media/mojo/clients/mojo_renderer_wrapper.h
media/mojo/mojom/renderer.mojom
media/mojo/services/mojo_renderer_service.cc
media/mojo/services/mojo_renderer_service.h
third_party/blink/renderer/platform/media/web_media_player_impl.cc
third_party/blink/renderer/platform/media/web_media_player_impl.h
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h
tizen_src/chromium_impl/media/filters/media_player_esplusplayer_tv.cc
tizen_src/chromium_impl/media/filters/media_player_tizen.h

index 0a1260e..d0bbafb 100644 (file)
@@ -320,6 +320,7 @@ class MEDIA_EXPORT Pipeline {
   virtual void SetActiveAudioTrack(int index) = 0;
   virtual void SetActiveVideoTrack(int index) = 0;
   virtual void SetPreferTextLanguage(const std::string& lang) = 0;
+  virtual void DestroyPlayerSync(base::OnceClosure cb) = 0;
 #endif
 };
 
index 05d72c1..49553d2 100644 (file)
@@ -121,6 +121,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   void SetActiveAudioTrack(int index);
   void SetActiveVideoTrack(int index);
   void SetPreferTextLanguage(const std::string& lang);
+  void DestroyPlayerSync(base::OnceClosure cb);
 #endif
 
   // |enabled_track_ids| contains track ids of enabled audio tracks.
@@ -192,6 +193,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
 #if BUILDFLAG(IS_TIZEN_TV)
   void NotifyTrackInfoToBrowser(int active_track_id) final;
   void AddTrackInfo(media::MediaTrackInfo trackinfo);
+  void PlayerDestroyed();
 #endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason) final;
@@ -294,6 +296,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
 #if BUILDFLAG(IS_TIZEN_TV)
   std::string mime_type_;
   std::unique_ptr<DecryptingMediaResource> decrypting_media_resource_{nullptr};
+  base::OnceClosure player_destroy_cb_;
 #endif
 
   // Whether we've received the audio/video ended events.
@@ -789,6 +792,31 @@ void PipelineImpl::RendererWrapper::
       base::BindRepeating(&RendererWrapper::OnWaiting,
                           weak_factory_.GetWeakPtr()));
 }
+void PipelineImpl::RendererWrapper::DestroyPlayerSync(base::OnceClosure cb) {
+  DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") ;" << __func__;
+
+  // If we destory during starting/seeking/suspending/resuming we don't want to
+  // leave outstanding callbacks around
+  pending_callbacks_.reset();
+
+  player_destroy_cb_ = std::move(cb);
+  if (shared_state_.renderer) {
+    shared_state_.renderer->DestroyPlayerSync(base::BindOnce(
+        &RendererWrapper::PlayerDestroyed, weak_factory_.GetWeakPtr()));
+  } else {
+    LOG(INFO) << "(" << static_cast<void*>(this) << ") ;" << __func__
+              << ", shared_state_.renderer is null";
+    std::move(player_destroy_cb_).Run();
+  }
+}
+
+void PipelineImpl::RendererWrapper::PlayerDestroyed() {
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") ;"
+            << "signal: player is destroyed";
+  // signal
+  std::move(player_destroy_cb_).Run();
+}
 #endif
 
 void PipelineImpl::RendererWrapper::CreateRendererInternal(
@@ -1898,6 +1926,16 @@ void PipelineImpl::SetCdm(CdmContext* cdm_context,
           base::BindPostTaskToCurrentDefault(std::move(cdm_attached_cb))));
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void PipelineImpl::DestroyPlayerSync(base::OnceClosure cb) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  media_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererWrapper::DestroyPlayerSync,
+                     base::Unretained(renderer_wrapper_.get()), std::move(cb)));
+}
+#endif
+
 #if defined(TIZEN_MULTIMEDIA)
 void PipelineImpl::ToggleFullscreenMode(bool is_fullscreen,
                                         ToggledFullscreenCB cb) {
index c933533..dfe55b6 100644 (file)
@@ -183,6 +183,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
   void SetActiveAudioTrack(int index) override;
   void SetActiveVideoTrack(int index) override;
   void SetPreferTextLanguage(const std::string& lang) override;
+  void DestroyPlayerSync(base::OnceClosure cb) override;
 #endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason);
index bde538a..6884f6a 100644 (file)
@@ -114,6 +114,7 @@ class MEDIA_EXPORT Renderer {
   virtual void SetActiveAudioTrack(int index) {}
   virtual void SetActiveVideoTrack(int index) {}
   virtual void SetPreferTextLanguage(const std::string& lang) {}
+  virtual void DestroyPlayerSync(base::OnceClosure cb) {}
 #endif
 
   // Starts rendering from |time|.
index eed47f6..1128216 100644 (file)
@@ -521,5 +521,14 @@ void PipelineController::SetPreferTextLanguage(const std::string& lang) {
   }
   pipeline_->SetPreferTextLanguage(lang);
 }
+
+void PipelineController::DestroyPlayerSync(base::OnceClosure cb) {
+  if (pipeline_) {
+    pipeline_->DestroyPlayerSync(std::move(cb));
+  } else {
+    LOG(ERROR) << "pipeline_ is null";
+    std::move(cb).Run();
+  }
+}
 #endif
 }  // namespace media
index 113d8bb..6e678c1 100644 (file)
@@ -170,6 +170,7 @@ class MEDIA_EXPORT PipelineController {
   void SetActiveAudioTrack(int index);
   void SetActiveVideoTrack(int index);
   void SetPreferTextLanguage(const std::string& lang);
+  void DestroyPlayerSync(base::OnceClosure cb);
 #endif
  private:
   // Attempts to make progress from the current state to the target state.
index 55c5084..4f4f7f2 100644 (file)
@@ -400,6 +400,26 @@ void MojoRenderer::SetPreferTextLanguage(const std::string& lang) {
   }
   remote_renderer_->SetPreferTextLanguage(lang);
 }
+
+void MojoRenderer::DestroyPlayerSync(base::OnceClosure cb) {
+  DVLOG(2) << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(remote_renderer_.is_bound());
+  DCHECK(cb);
+  DCHECK(!player_destroy_cb_);
+
+  player_destroy_cb_ = std::move(cb);
+  remote_renderer_->DestroyPlayerSync(
+      base::BindOnce(&MojoRenderer::OnPlayerDestroyed, base::Unretained(this)));
+}
+
+void MojoRenderer::OnPlayerDestroyed() {
+  LOG(INFO) << "OnPlayerDestroyed";
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(player_destroy_cb_);
+
+  std::move(player_destroy_cb_).Run();
+}
 #endif
 
 void MojoRenderer::OnWaiting(WaitingReason reason) {
index aa08217..53c9754 100644 (file)
@@ -83,6 +83,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   void SetActiveAudioTrack(int index) override;
   void SetActiveVideoTrack(int index) override;
   void SetPreferTextLanguage(const std::string& lang) override;
+  void DestroyPlayerSync(base::OnceClosure cb) override;
 #endif
 
  private:
@@ -138,6 +139,10 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   void OnSeekCompleted();
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  void OnPlayerDestroyed();
+#endif
+
   void CancelPendingCallbacks();
 
   // |task_runner| on which all methods are invoked, except for GetMediaTime(),
@@ -189,6 +194,10 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   base::OnceClosure seek_cb_;
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  base::OnceClosure player_destroy_cb_;
+#endif
+
   float volume_ = 1.0f;
 
   // Lock used to serialize access for |time_interpolator_|.
index 4f1c591..548e650 100644 (file)
@@ -111,6 +111,15 @@ void MojoRendererWrapper::SetPreferTextLanguage(const std::string& lang) {
   if (mojo_renderer_)
     mojo_renderer_->SetPreferTextLanguage(lang);
 }
+
+void MojoRendererWrapper::DestroyPlayerSync(base::OnceClosure cb) {
+  if (mojo_renderer_) {
+    mojo_renderer_->DestroyPlayerSync(std::move(cb));
+  } else {
+    LOG(ERROR) << "mojo_renderer_ is null";
+    std::move(cb).Run();
+  }
+}
 #endif
 
 }  // namespace media
index fb68130..719b0e1 100644 (file)
@@ -55,6 +55,7 @@ class MojoRendererWrapper : public Renderer {
   void SetActiveVideoTrack(int index) override;
   void SetActiveAudioTrack(int index) override;
   void SetPreferTextLanguage(const std::string& lang) override;
+  void DestroyPlayerSync(base::OnceClosure cb) override;
 #endif
 
   base::TimeDelta GetMediaTime() override;
index 71979eb..7c83186 100644 (file)
@@ -85,6 +85,9 @@ interface Renderer {
 
   [EnableIf=is_tizen_tv]
   SetPreferTextLanguage(string lang);
+
+  [EnableIf=is_tizen_tv]
+  DestroyPlayerSync() => ();
 };
 
 // A Mojo equivalent of media::RendererClient. See media/mojo/README.md
index 5537033..43333c8 100644 (file)
@@ -259,6 +259,24 @@ void MojoRendererService::SetPreferTextLanguage(const std::string& lang) {
   }
   renderer_->SetPreferTextLanguage(lang);
 }
+
+void MojoRendererService::OnPlayerDestroyed(base::OnceClosure destroy_cb) {
+  LOG(INFO) << "OnPlayerDestroyed";
+  std::move(destroy_cb).Run();
+}
+
+void MojoRendererService::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+  DVLOG(2) << __func__;
+
+  if (renderer_) {
+    renderer_->DestroyPlayerSync(
+        base::BindOnce(&MojoRendererService::OnPlayerDestroyed, weak_this_,
+                       std::move(destroy_cb)));
+  } else {
+    LOG(ERROR) << "renderer_ is null";
+    std::move(destroy_cb).Run();
+  }
+}
 #endif
 
 void MojoRendererService::OnBufferingStateChange(
index afc535a..0dda352 100644 (file)
@@ -89,6 +89,7 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer,
   void SetActiveAudioTrack(int index) final;
   void SetActiveVideoTrack(int index) final;
   void SetPreferTextLanguage(const std::string& lang) final;
+  void DestroyPlayerSync(base::OnceClosure destroy_cb) final;
 #endif
 
  private:
@@ -105,6 +106,9 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer,
   void OnFallback(PipelineStatus status) final;
   void OnEnded() final;
   void OnStatisticsUpdate(const PipelineStatistics& stats) final;
+#if BUILDFLAG(IS_TIZEN_TV)
+  void OnPlayerDestroyed(base::OnceClosure destroy_cb);
+#endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason) final;
   void OnWaiting(WaitingReason reason) final;
index b632c01..2e8bdd1 100644 (file)
@@ -34,6 +34,7 @@
 #include "build/build_config.h"
 #include "cc/layers/video_layer.h"
 #include "components/viz/common/gpu/raster_context_provider.h"
+#include "content/public/common/content_switches.h"
 #include "media/audio/null_audio_sink.h"
 #include "media/base/audio_renderer_sink.h"
 #include "media/base/cdm_context.h"
@@ -609,6 +610,25 @@ WebMediaPlayerImpl::~WebMediaPlayerImpl() {
                                  std::move(media_thread_mem_dumper_));
   main_thread_mem_dumper_.reset();
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // for app eme case, we must ensure player is destroyed before IEMEDrmBridge
+  // PipelineController::Stop will destroy player by mojom IPC and destroy
+  // finish time is not fixed Now we split the original PipelineController::Stop
+  // fuction to 2 parts:
+  // 1. DestroyPlayerSync only destroy MediaPlayerESPlusPlayer
+  // 2. Stop is the same with the original logic except 1, such as destroy
+  // MediaPlayerRendererClient/MojoRendererWrapper/MojoRenderer/MojoRendererService
+  // /TizenRendererImpl
+  if (IsSyncDestroyPlayerNeeded()) {
+    LOG(INFO) << "need destroy player sync...";
+    base::WaitableEvent waiter(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+                               base::WaitableEvent::InitialState::NOT_SIGNALED);
+    pipeline_controller_->DestroyPlayerSync(base::BindOnce(
+        &base::WaitableEvent::Signal, base::Unretained(&waiter)));
+    waiter.Wait();
+  }
+#endif
+
   // The underlying Pipeline must be stopped before it is destroyed.
   //
   // Note: This destruction happens synchronously on the media thread and
@@ -2261,6 +2281,15 @@ void WebMediaPlayerImpl::SetActiveVideoTrack(int index) {
 void WebMediaPlayerImpl::SetPreferTextLanguage(const std::string& lang) {
   pipeline_controller_->SetPreferTextLanguage(lang);
 }
+
+bool WebMediaPlayerImpl::IsSyncDestroyPlayerNeeded() {
+  bool single_process_mode = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSingleProcess);
+  bool isMSE = load_type_ == kLoadTypeMediaSource;
+  if (isMSE && single_process_mode && cdm_context_ref_)
+    return true;
+  return false;
+}
 #endif
 
 bool WebMediaPlayerImpl::CanPlayThrough() {
index e4b2115..834286d 100644 (file)
@@ -533,6 +533,10 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   // Can return a nullptr.
   scoped_refptr<media::VideoFrame> GetCurrentFrameFromCompositor() const;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  bool IsSyncDestroyPlayerNeeded();
+#endif
+
   // Sets CdmContext from |cdm| on the pipeline and calls OnCdmAttached()
   // when done.
   void SetCdmInternal(WebContentDecryptionModule* cdm);
index a09bc9f..53c0d5a 100644 (file)
@@ -577,6 +577,17 @@ void TizenRendererImpl::SetParentalRatingResult(bool is_pass) {
     LOG_ID(ERROR, player_id_) << "media_player_ is null";
 }
 
+void TizenRendererImpl::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+  if (media_player_) {
+    media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
+        player_id_, !resource_conflicted_);
+    media_player_->DestroyPlayerSync(std::move(destroy_cb));
+  } else {
+    LOG_ID(INFO, player_id_) << "media_player_ is nullptr";
+    std::move(destroy_cb).Run();
+  }
+}
+
 bool TizenRendererImpl::PlaybackNotificationEnabled() {
   content::WebContents* web_contents = GetWebContents();
   if (!web_contents) {
index 8208990..bc29db0 100644 (file)
@@ -159,6 +159,7 @@ class CONTENT_EXPORT TizenRendererImpl
 #if BUILDFLAG(IS_TIZEN_TV)
   void SetContentMimeType(const std::string& mime_type) override;
   void SetParentalRatingResult(bool is_pass) override;
+  void DestroyPlayerSync(base::OnceClosure destroy_cb) override;
 #endif
 
  private:
index e091b85..6b1d9f3 100644 (file)
@@ -128,7 +128,15 @@ MediaPlayerESPlusPlayer::MediaPlayerESPlusPlayer() {
 }
 
 MediaPlayerESPlusPlayer::~MediaPlayerESPlusPlayer() {
-  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (!esplayer_) {
+    LOG_ID(INFO, player_id_) << "player is already destroyed:" << (void*)this;
+    return;
+  }
+#endif
+
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                           << __func__;
   weak_factory_.InvalidateWeakPtrs();
 
   // Player should be released before destroyed.
@@ -142,6 +150,32 @@ MediaPlayerESPlusPlayer::~MediaPlayerESPlusPlayer() {
   esplayer_ = nullptr;
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void MediaPlayerESPlusPlayer::DestroyPlayerSync(base::OnceClosure destroy_cb) {
+  if (!esplayer_) {
+    LOG_ID(INFO, player_id_) << "player is already destroyed:" << (void*)this;
+    std::move(destroy_cb).Run();
+    return;
+  }
+
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                           << __func__;
+  weak_factory_.InvalidateWeakPtrs();
+
+  Release();
+
+  int error = esplusplayer_destroy(esplayer_);
+  if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
+    LOG_ID(ERROR, player_id_)
+        << "esplusplayer_destroy failed, error #"
+        << esplusplayer_get_error_string(
+               static_cast<esplusplayer_error_type>(error));
+  esplayer_ = nullptr;
+
+  std::move(destroy_cb).Run();
+}
+#endif
+
 bool MediaPlayerESPlusPlayer::CreatePlayer(int player_id) {
   player_id_ = player_id;
 
@@ -174,10 +208,11 @@ bool MediaPlayerESPlusPlayer::CreatePlayer(int player_id) {
 }
 
 void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
-  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                           << __func__;
 
   if (!esplayer_) {
-    LOG(INFO) << "(" << static_cast<void*>(this) << ") "
+    LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                              << "esplayer is null.";
     return;
   }
@@ -239,8 +274,14 @@ void MediaPlayerESPlusPlayer::SetStreamInfo(DemuxerStream::Type type,
 
 void MediaPlayerESPlusPlayer::Prepare() {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
-  if (!esplayer_ || is_prepared_ || is_preparing_)
+  if (!esplayer_ || is_prepared_ || is_preparing_) {
+    LOG_ID(ERROR, player_id_)
+        << "(" << static_cast<void*>(this) << ") " << __func__
+        << ", esplayer_: " << static_cast<void*>(esplayer_)
+        << ", is_prepared_: " << is_prepared_
+        << ", is_preparing_: " << is_preparing_;
     return;
+  }
 
   if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
@@ -274,7 +315,7 @@ bool MediaPlayerESPlusPlayer::IsPrepared() {
 }
 
 bool MediaPlayerESPlusPlayer::CanPrepare() {
-  return !IsPrepared() && !is_preparing_;
+  return esplayer_ && !IsPrepared() && !is_preparing_;
 }
 
 void MediaPlayerESPlusPlayer::Release() {
@@ -1403,7 +1444,7 @@ void MediaPlayerESPlusPlayer::SetMediaGeometry(const gfx::Rect& viewport_rect,
             << " rect : " << rect.ToString();
 
   if (!esplayer_ || !video_plane_controller_) {
-    LOG(INFO)
+    LOG_ID(INFO, player_id_)
         << "(" << static_cast<void*>(this) << ") "
         << "player is destroyed, or video plane controller not exist.";
     return;
@@ -1413,10 +1454,16 @@ void MediaPlayerESPlusPlayer::SetMediaGeometry(const gfx::Rect& viewport_rect,
 }
 
 void MediaPlayerESPlusPlayer::PrepareVideoHole() {
-  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
-  if (!esplayer_ || is_prepared_ || is_preparing_)
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                           << __func__;
+  if (!esplayer_ || is_prepared_ || is_preparing_) {
+    LOG_ID(ERROR, player_id_)
+        << "(" << static_cast<void*>(this) << ") " << __func__
+        << ", esplayer_: " << static_cast<void*>(esplayer_)
+        << ", is_prepared_: " << is_prepared_
+        << ", is_preparing_: " << is_preparing_;
     return;
-
+  }
   if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
     LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
                << " Prepare called on invalid state : "
index a8e9c59..ec62e6b 100644 (file)
@@ -85,6 +85,10 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen {
   void DestroyMediaPacket(void* media_packet) override;
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  void DestroyPlayerSync(base::OnceClosure destroy_cb) override;
+#endif
+
   // Callback handler
   void OnReadyToPrepare(const esplusplayer_stream_type stream_type);
   virtual void OnPrepareComplete(bool result);
index 84361c1..c781940 100644 (file)
@@ -30,6 +30,13 @@ MediaPlayerESPlusPlayerTV::~MediaPlayerESPlusPlayerTV() {
 
 void MediaPlayerESPlusPlayerTV::Initialize(VideoRendererSink* sink) {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+
+  if (!esplayer_) {
+    LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                             << "esplayer is null.";
+    return;
+  }
+
   single_process_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kSingleProcess);
   MediaPlayerESPlusPlayer::Initialize(sink);
@@ -41,6 +48,12 @@ void MediaPlayerESPlusPlayerTV::InitializeStreamConfig(
     DemuxerStream::Type type) {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
 
+  if (!esplayer_) {
+    LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                             << "esplayer is null.";
+    return;
+  }
+
   MediaPlayerESPlusPlayer::InitializeStreamConfig(type);
 }
 
index d24ffc6..0fbfcb6 100644 (file)
@@ -116,6 +116,9 @@ class MEDIA_EXPORT MediaPlayerTizen {
   virtual void SetActiveVideoTrack(int index) {}
   virtual void SetPreferTextLanguage(const std::string& lang) {}
   virtual void UpdateEventData(std::string data) {}
+#if BUILDFLAG(IS_TIZEN_TV)
+  virtual void DestroyPlayerSync(base::OnceClosure destroy_cb) {}
+#endif
 };
 }  // namespace media