From 54c952fb56a170b1ae1b733f37393308607a28dd Mon Sep 17 00:00:00 2001 From: "sangdeug.kim" Date: Wed, 21 Jan 2015 19:58:31 +0900 Subject: [PATCH] [MM]EME implementation using EncryptedMediaPlayerSupport. SHA:aaaae22e commit is included to fix crash issue. (Refactor MediaSourceDelegate destruction.) https://codereview.chromium.org/605013002 Together with: I0e3d41130d1b66e32e248a2ac6495c5d52cd9e8f Bug: http://107.108.218.239/bugzilla/show_bug.cgi?id=8682 Reviewed by: Min-Soo Koo, SeungSeop Park, Venugopal S M Change-Id: I9c065ae4a9b442bf5141011e66aa7f4135cc8b65 Signed-off-by: sangdeug.kim --- .../media/tizen/media_source_delegate_tizen.cc | 146 +++++++++++++++++---- .../media/tizen/media_source_delegate_tizen.h | 39 ++++-- .../impl/media/base/tizen/webmediaplayer_tizen.cc | 68 +++++++++- .../impl/media/base/tizen/webmediaplayer_tizen.h | 36 ++++- 4 files changed, 241 insertions(+), 48 deletions(-) diff --git a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc index 914d0ae..8a14751 100644 --- a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc +++ b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.cc @@ -57,15 +57,21 @@ MediaSourceDelegateTizen::~MediaSourceDelegateTizen() { DCHECK(!chunk_demuxer_); DCHECK(!audio_stream_); DCHECK(!video_stream_); + DCHECK(!audio_decrypting_demuxer_stream_); + DCHECK(!video_decrypting_demuxer_stream_); } void MediaSourceDelegateTizen::InitializeMediaSource( const MediaSourceOpenedCB& media_source_opened_cb, + const media::Demuxer::NeedKeyCB& need_key_cb, + const media::SetDecryptorReadyCB& set_decryptor_ready_cb, const UpdateNetworkStateCB& update_network_state_cb, const DurationChangeCB& duration_change_cb) { DCHECK(main_loop_->BelongsToCurrentThread()); DCHECK(!media_source_opened_cb.is_null()); media_source_opened_cb_ = media_source_opened_cb; + need_key_cb_ = need_key_cb; + set_decryptor_ready_cb_ = set_decryptor_ready_cb; update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb); duration_change_cb_ = duration_change_cb; @@ -95,8 +101,11 @@ void MediaSourceDelegateTizen::InitializeDemuxer() { void MediaSourceDelegateTizen::OnNeedKey( const std::string& type, const std::vector& init_data) { - // FIXME: Need to check the functionality of this method. - NOTIMPLEMENTED(); + DCHECK(main_loop_->BelongsToCurrentThread()); + if (need_key_cb_.is_null()) { + return; + } + need_key_cb_.Run(type, init_data); } void MediaSourceDelegateTizen::OnDemuxerOpened() { @@ -113,11 +122,6 @@ void MediaSourceDelegateTizen::OnDemuxerError( update_network_state_cb_.Run(PipelineErrorToNetworkState(status)); } -bool MediaSourceDelegateTizen::CanNotifyDemuxerReady() { - DCHECK(media_task_runner_->BelongsToCurrentThread()); - return is_demuxer_ready_; -} - void MediaSourceDelegateTizen::OnDemuxerInitDone( media::PipelineStatus status) { DCHECK(media_task_runner_->BelongsToCurrentThread()); @@ -128,21 +132,84 @@ void MediaSourceDelegateTizen::OnDemuxerInitDone( } audio_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::AUDIO); video_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::VIDEO); - if ((audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted()) - || (video_stream_ && video_stream_->video_decoder_config().is_encrypted() - )) { - OnDemuxerError(media::PIPELINE_ERROR_DECODE); + if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() && + !set_decryptor_ready_cb_.is_null()) { + InitAudioDecryptingDemuxerStream(); + return; + } + if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() && + !set_decryptor_ready_cb_.is_null()) { + InitVideoDecryptingDemuxerStream(); return; } - // Notify demuxer ready when both streams are not encrypted. is_demuxer_ready_ = true; NotifyDemuxerReady(); } +void MediaSourceDelegateTizen::InitAudioDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( + media_task_runner_, set_decryptor_ready_cb_)); + + audio_decrypting_demuxer_stream_->Initialize( + audio_stream_, + base::Bind(&MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone, + media_weak_factory_.GetWeakPtr())); +} + +void MediaSourceDelegateTizen::InitVideoDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + + video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream( + media_task_runner_, set_decryptor_ready_cb_)); + + video_decrypting_demuxer_stream_->Initialize( + video_stream_, + base::Bind(&MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone, + media_weak_factory_.GetWeakPtr())); +} + + +void MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + + if (status != media::PIPELINE_OK) + audio_decrypting_demuxer_stream_.reset(); + else + audio_stream_ = audio_decrypting_demuxer_stream_.get(); + + if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) { + InitVideoDecryptingDemuxerStream(); + return; + } + + // Try to notify demuxer ready when audio DDS initialization finished and + // video is not encrypted. + is_demuxer_ready_ = true; + NotifyDemuxerReady(); +} + +void MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone( + media::PipelineStatus status) { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(chunk_demuxer_); + + if (status != media::PIPELINE_OK) + video_decrypting_demuxer_stream_.reset(); + else + video_stream_ = video_decrypting_demuxer_stream_.get(); + + // Try to notify demuxer ready when video DDS initialization finished. + is_demuxer_ready_ = true; + NotifyDemuxerReady(); +} + void MediaSourceDelegateTizen::NotifyDemuxerReady() { DCHECK(media_task_runner_->BelongsToCurrentThread()); - DCHECK(CanNotifyDemuxerReady()); + DCHECK(is_demuxer_ready_); scoped_ptr configs(new media::DemuxerConfigs()); if (audio_stream_) { @@ -194,14 +261,13 @@ void MediaSourceDelegateTizen::OnReadFromDemuxer( } } -void MediaSourceDelegateTizen::Destroy() { +void MediaSourceDelegateTizen::Stop(const base::Closure& stop_cb) { DCHECK(main_loop_->BelongsToCurrentThread()); VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__ << ": Demuxer Client Id = " << demuxer_client_id_; if (!chunk_demuxer_) { DCHECK(!demuxer_client_); - delete this; return; } @@ -219,10 +285,11 @@ void MediaSourceDelegateTizen::Destroy() { media_task_runner_->PostTask( FROM_HERE, base::Bind(&MediaSourceDelegateTizen::StopDemuxer, - base::Unretained(this))); + base::Unretained(this), + stop_cb)); } -void MediaSourceDelegateTizen::StopDemuxer() { +void MediaSourceDelegateTizen::StopDemuxer(const base::Closure& stop_cb) { DCHECK(media_task_runner_->BelongsToCurrentThread()); DCHECK(chunk_demuxer_); @@ -230,6 +297,8 @@ void MediaSourceDelegateTizen::StopDemuxer() { demuxer_client_ = NULL; audio_stream_ = NULL; video_stream_ = NULL; + audio_decrypting_demuxer_stream_.reset(); + video_decrypting_demuxer_stream_.reset(); media_weak_factory_.InvalidateWeakPtrs(); DCHECK(!media_weak_factory_.HasWeakPtrs()); @@ -237,18 +306,7 @@ void MediaSourceDelegateTizen::StopDemuxer() { chunk_demuxer_->Stop(); chunk_demuxer_.reset(); - main_loop_->PostTask( - FROM_HERE, - base::Bind(&MediaSourceDelegateTizen::DeleteSelf, - base::Unretained(this))); -} - -void MediaSourceDelegateTizen::DeleteSelf() { - DCHECK(main_loop_->BelongsToCurrentThread()); - VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__ - << ": Demuxer Client Id = " << demuxer_client_id_; - chunk_demuxer_.reset(); - delete this; + stop_cb.Run(); } void MediaSourceDelegateTizen::OnMediaConfigRequest() { @@ -404,6 +462,36 @@ void MediaSourceDelegateTizen::OnDemuxerSeekDone( is_demuxer_seek_done_ = true; demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); } + ResetAudioDecryptingDemuxerStream(); +} + +void MediaSourceDelegateTizen::ResetAudioDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + if (audio_decrypting_demuxer_stream_) { + audio_decrypting_demuxer_stream_->Reset( + base::Bind(&MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream, + media_weak_factory_.GetWeakPtr())); + return; + } + ResetVideoDecryptingDemuxerStream(); +} + +void MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + if (video_decrypting_demuxer_stream_) { + video_decrypting_demuxer_stream_->Reset(base::Bind( + &MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams, + media_weak_factory_.GetWeakPtr())); + return; + } + FinishResettingDecryptingDemuxerStreams(); +} + +void MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams() { + DCHECK(media_task_runner_->BelongsToCurrentThread()); + DCHECK(is_seeking_); + is_seeking_ = false; + demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_); } void MediaSourceDelegateTizen::SetDuration(base::TimeDelta duration) { diff --git a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h index 1caf259..8727771 100644 --- a/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h +++ b/tizen_src/impl/content/renderer/media/tizen/media_source_delegate_tizen.h @@ -10,6 +10,7 @@ #include "media/base/demuxer_stream.h" #include "media/base/media_keys.h" #include "media/filters/chunk_demuxer.h" +#include "media/filters/decrypting_demuxer_stream.h" #include "third_party/WebKit/public/platform/WebMediaPlayer.h" namespace content { @@ -23,14 +24,6 @@ public: UpdateNetworkStateCB; typedef base::Callback DurationChangeCB; - class Destroyer { - public: - inline void operator()(void* media_source_delegate) const { - static_cast( - media_source_delegate)->Destroy(); - } - }; - MediaSourceDelegateTizen( RendererDemuxerTizen* demuxer_client, int demuxer_client_id, @@ -61,14 +54,16 @@ public: void InitializeMediaSource( const MediaSourceOpenedCB& media_source_opened_cb, + const media::Demuxer::NeedKeyCB& need_key_cb, + const media::SetDecryptorReadyCB& set_decryptor_ready_cb, const UpdateNetworkStateCB& update_network_state_cb, const DurationChangeCB& duration_change_cb); // Called when DemuxerStreamPlayer needs to read data from ChunkDemuxer. void OnReadFromDemuxer(media::DemuxerStream::Type type); - // Called by the Destroyer to destroy an instance of this object. - void Destroy(); + // Must be called explicitly before |this| can be destroyed. + void Stop(const base::Closure& stop_cb); // In MSE case, calls ChunkDemuxer::StartWaitingForSeek(), sets the // expectation that a regular seek will be arriving. @@ -97,10 +92,10 @@ public: void OnDemuxerOpened(); void InitializeDemuxer(); void OnDemuxerInitDone(media::PipelineStatus status); - void StopDemuxer(); - void DeleteSelf(); - bool CanNotifyDemuxerReady(); + // Stops and clears objects on the media thread. + void StopDemuxer(const base::Closure& stop_cb); + void NotifyDemuxerReady(); void OnDurationChanged(const base::TimeDelta& duration); void OnBufferReady( @@ -109,6 +104,19 @@ public: const scoped_refptr& buffer); void SeekInternal(const base::TimeDelta& seek_time); + // Initializes DecryptingDemuxerStreams if audio/video stream is encrypted. + void InitAudioDecryptingDemuxerStream(); + void InitVideoDecryptingDemuxerStream(); + + // Callbacks for DecryptingDemuxerStream::Initialize(). + void OnAudioDecryptingDemuxerStreamInitDone(media::PipelineStatus status); + void OnVideoDecryptingDemuxerStreamInitDone(media::PipelineStatus status); + + // Runs on the media thread. + void ResetAudioDecryptingDemuxerStream(); + void ResetVideoDecryptingDemuxerStream(); + void FinishResettingDecryptingDemuxerStreams(); + // Message loop for main renderer thread and corresponding weak pointer. const scoped_refptr main_loop_; base::WeakPtrFactory main_weak_factory_; @@ -129,6 +137,11 @@ public: media::DemuxerStream* audio_stream_; media::DemuxerStream* video_stream_; + media::SetDecryptorReadyCB set_decryptor_ready_cb_; + media::Demuxer::NeedKeyCB need_key_cb_; + scoped_ptr audio_decrypting_demuxer_stream_; + scoped_ptr video_decrypting_demuxer_stream_; + base::TimeDelta seek_time_; bool pending_seek_; bool is_seeking_; diff --git a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc index 76f7b62..a6faa8b 100644 --- a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc +++ b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.cc @@ -50,9 +50,10 @@ GURL GetCleanURL(std::string url) { WebMediaPlayerTizen::WebMediaPlayerTizen( content::RendererMediaPlayerManagerTizen* manager, - blink::WebFrame* frame, + blink::WebLocalFrame* frame, blink::WebMediaPlayerClient* client, base::WeakPtr delegate, + const WebMediaPlayerParams& params, content::WrtUrlParseBase* wrt_url_parse) : frame_(frame), network_state_(blink::WebMediaPlayer::NetworkStateEmpty), @@ -85,8 +86,11 @@ WebMediaPlayerTizen::WebMediaPlayerTizen( did_loading_progress_(false), volume_(0), gpu_factories_(content::RenderThreadImpl::current()->GetGpuFactories()), + encrypted_media_support_( + params.CreateEncryptedMediaPlayerSupport(client)), wrt_url_parse_(wrt_url_parse) { DCHECK(manager_); + DCHECK(encrypted_media_support_); VLOG(1) << "WebMediaPlayerTizen::" << __FUNCTION__; FrameAvailable_ = false; // We want to be notified of |main_loop_| destruction. @@ -116,6 +120,16 @@ WebMediaPlayerTizen::~WebMediaPlayerTizen() { if (base::MessageLoop::current()) base::MessageLoop::current()->RemoveDestructionObserver(this); compositor_task_runner_->DeleteSoon(FROM_HERE, compositor_); + if (media_source_delegate_) { + // Part of |media_source_delegate_| needs to be stopped + // on the media thread. + // Wait until |media_source_delegate_| is fully stopped + // before tearing down other objects. + base::WaitableEvent waiter(false, false); + media_source_delegate_->Stop( + base::Bind(&base::WaitableEvent::Signal, base::Unretained(&waiter))); + waiter.Wait(); + } } void WebMediaPlayerTizen::load(LoadType load_type, @@ -134,9 +148,15 @@ void WebMediaPlayerTizen::load(LoadType load_type, demuxer_client_id = demuxer->GetNextDemuxerClientID(); media_source_delegate_.reset(new content::MediaSourceDelegateTizen( demuxer, demuxer_client_id, media_task_runner_, media_log_.get())); + SetDecryptorReadyCB set_decryptor_ready_cb = + encrypted_media_support_->CreateSetDecryptorReadyCB(); + Demuxer::NeedKeyCB need_key_cb = + encrypted_media_support_->CreateNeedKeyCB(); media_source_delegate_->InitializeMediaSource( base::Bind(&WebMediaPlayerTizen::OnMediaSourceOpened, weak_factory_.GetWeakPtr()), + need_key_cb, + set_decryptor_ready_cb, base::Bind(&WebMediaPlayerTizen::SetNetworkState, weak_factory_.GetWeakPtr()), base::Bind(&WebMediaPlayerTizen::OnDurationChange, @@ -166,6 +186,52 @@ void WebMediaPlayerTizen::load(LoadType load_type, demuxer_client_id); } +blink::WebMediaPlayer::MediaKeyException +WebMediaPlayerTizen::generateKeyRequest(const blink::WebString& key_system, + const unsigned char* init_data, + unsigned init_data_length) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->GenerateKeyRequest( + frame_, key_system, init_data, init_data_length); +} + +blink::WebMediaPlayer::MediaKeyException WebMediaPlayerTizen::addKey( + const blink::WebString& key_system, + const unsigned char* key, + unsigned key_length, + const unsigned char* init_data, + unsigned init_data_length, + const blink::WebString& session_id) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->AddKey( + key_system, key, key_length, init_data, init_data_length, session_id); +} + +blink::WebMediaPlayer::MediaKeyException WebMediaPlayerTizen::cancelKeyRequest( + const blink::WebString& key_system, + const blink::WebString& session_id) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + return encrypted_media_support_->CancelKeyRequest(key_system, session_id); +} + +void WebMediaPlayerTizen::setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + encrypted_media_support_->SetContentDecryptionModule(cdm); +} + +void WebMediaPlayerTizen::setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm, + blink::WebContentDecryptionModuleResult result) { + DCHECK(main_loop_->BelongsToCurrentThread()); + + encrypted_media_support_->SetContentDecryptionModule(cdm, result); +} + void WebMediaPlayerTizen::OnMediaSourceOpened( blink::WebMediaSource* web_media_source) { client_->mediaSourceOpened(web_media_source); diff --git a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h index f404ae1..cb1a12a 100644 --- a/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h +++ b/tizen_src/impl/media/base/tizen/webmediaplayer_tizen.h @@ -10,10 +10,11 @@ #include "content/renderer/media/tizen/media_source_delegate_tizen.h" #include "content/renderer/media/tizen/renderer_media_player_manager_tizen.h" #include "media/blink/video_frame_compositor.h" +#include "media/blink/webmediaplayer_params.h" #include "media/filters/skcanvas_video_renderer.h" namespace blink { -class WebFrame; +class WebLocalFrame; } namespace cc_blink { @@ -45,9 +46,10 @@ class WebMediaPlayerTizen // |proxy|. WebMediaPlayerTizen( content::RendererMediaPlayerManagerTizen* manager, - blink::WebFrame* frame, + blink::WebLocalFrame* frame, blink::WebMediaPlayerClient* client, base::WeakPtr delegate, + const WebMediaPlayerParams& params, content::WrtUrlParseBase* wrt_url_parse); virtual ~WebMediaPlayerTizen(); @@ -110,6 +112,30 @@ class WebMediaPlayerTizen // Method inherited from DestructionObserver. virtual void WillDestroyCurrentMessageLoop() override {}; + virtual MediaKeyException generateKeyRequest( + const blink::WebString& key_system, + const unsigned char* init_data, + unsigned init_data_length); + + virtual MediaKeyException addKey(const blink::WebString& key_system, + const unsigned char* key, + unsigned key_length, + const unsigned char* init_data, + unsigned init_data_length, + const blink::WebString& session_id); + + virtual MediaKeyException cancelKeyRequest( + const blink::WebString& key_system, + const blink::WebString& session_id); + + // TODO(jrummell): Remove this method once Blink updated to use the other + // method. + virtual void setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm); + virtual void setContentDecryptionModule( + blink::WebContentDecryptionModule* cdm, + blink::WebContentDecryptionModuleResult result); + void SetReadyState(WebMediaPlayer::ReadyState state); void SetNetworkState(WebMediaPlayer::NetworkState state); @@ -146,7 +172,7 @@ class WebMediaPlayerTizen // Called whenever there is new frame to be painted. void FrameReady(const scoped_refptr& frame); - blink::WebFrame* frame_; + blink::WebLocalFrame* frame_; blink::WebMediaPlayer::NetworkState network_state_; blink::WebMediaPlayer::ReadyState ready_state_; @@ -177,8 +203,7 @@ class WebMediaPlayerTizen media::SkCanvasVideoRenderer skcanvas_video_renderer_; base::WeakPtrFactory weak_factory_; - scoped_ptr media_source_delegate_; + scoped_ptr media_source_delegate_; MediaPlayerHostMsg_Initialize_Type player_type_; // Player ID assigned by the |manager_|. @@ -211,6 +236,7 @@ class WebMediaPlayerTizen // Factories for supporting video accelerators. May be null. scoped_refptr gpu_factories_; + scoped_ptr encrypted_media_support_; content::WrtUrlParseBase* wrt_url_parse_; DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerTizen); -- 2.7.4