Chromium Code Reviews| Index: content/renderer/media/webmediaplayer_ms.cc |
| diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc |
| index 80bd723099090ab737278b2bbc21ffd751554805..96aff406716c6b4f2997a14f674d3103e84f58fd 100644 |
| --- a/content/renderer/media/webmediaplayer_ms.cc |
| +++ b/content/renderer/media/webmediaplayer_ms.cc |
| @@ -12,6 +12,7 @@ |
| #include "base/metrics/histogram.h" |
| #include "cc/blink/context_provider_web_context.h" |
| #include "cc/blink/web_layer_impl.h" |
| +#include "cc/layers/video_frame_provider_client_impl.h" |
| #include "cc/layers/video_layer.h" |
| #include "content/public/renderer/media_stream_audio_renderer.h" |
| #include "content/public/renderer/media_stream_renderer_factory.h" |
| @@ -93,7 +94,8 @@ WebMediaPlayerMS::WebMediaPlayerMS( |
| blink::WebMediaPlayerClient* client, |
| base::WeakPtr<media::WebMediaPlayerDelegate> delegate, |
| media::MediaLog* media_log, |
| - scoped_ptr<MediaStreamRendererFactory> factory) |
| + scoped_ptr<MediaStreamRendererFactory> factory, |
| + scoped_refptr<base::SingleThreadTaskRunner> compositor_thread) |
| : frame_(frame), |
| network_state_(WebMediaPlayer::NetworkStateEmpty), |
| ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| @@ -108,7 +110,9 @@ WebMediaPlayerMS::WebMediaPlayerMS( |
| total_frame_count_(0), |
| dropped_frame_count_(0), |
| media_log_(media_log), |
| - renderer_factory_(factory.Pass()) { |
| + renderer_factory_(factory.Pass()), |
| + compositor_thread_(compositor_thread), |
| + wait_event_(false,false) { |
| DVLOG(1) << "WebMediaPlayerMS::ctor"; |
| media_log_->AddEvent( |
| media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); |
| @@ -118,7 +122,20 @@ WebMediaPlayerMS::~WebMediaPlayerMS() { |
| DVLOG(1) << "WebMediaPlayerMS::dtor"; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - SetVideoFrameProviderClient(NULL); |
| + // Wait till stop procedure finishes to avoid the case that after |
| + // WebMediaPlayerMS is destroyed, VideoFrameProvider is still trying to access |
| + // it. |
| + |
| + if (video_frame_provider_client_){ |
| + compositor_thread_->PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &WebMediaPlayerMS::StopVideoFrameProviderAndWakeUpHelper, |
| + video_frame_provider_client_, |
| + &wait_event_)); |
| + wait_event_.Wait(); |
|
DaleCurtis
2015/08/13 18:06:53
Hmm, this is unfortunate. Typically you'd use Comp
qiangchen
2015/08/14 16:52:50
Done.
|
| + } |
| + |
| GetClient()->setWebLayer(NULL); |
| if (video_frame_provider_.get()) |
| @@ -187,6 +204,13 @@ void WebMediaPlayerMS::play() { |
| if (video_frame_provider_.get()) |
| video_frame_provider_->Play(); |
| + if (video_frame_provider_client_){ |
| + compositor_thread_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&WebMediaPlayerMS::StartRenderingHelper, |
| + video_frame_provider_client_)); |
| + } |
| + |
| if (audio_renderer_.get()) |
| audio_renderer_->Play(); |
| @@ -206,6 +230,13 @@ void WebMediaPlayerMS::pause() { |
| if (video_frame_provider_.get()) |
| video_frame_provider_->Pause(); |
| + if (video_frame_provider_client_){ |
| + compositor_thread_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&WebMediaPlayerMS::StopRenderingHelper, |
| + video_frame_provider_client_)); |
| + } |
| + |
| if (!paused_) { |
| if (audio_renderer_.get()) |
| audio_renderer_->Pause(); |
| @@ -449,16 +480,60 @@ void WebMediaPlayerMS::SetVideoFrameProviderClient( |
| // This is called from both the main renderer thread and the compositor |
| // thread (when the main thread is blocked). |
| if (video_frame_provider_client_) |
| - video_frame_provider_client_->StopUsingProvider(); |
| + compositor_thread_->PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &WebMediaPlayerMS::StopVideoFrameProviderHelper, |
| + video_frame_provider_client_)); |
| + |
| video_frame_provider_client_ = client; |
| + if (client && !paused_) |
| + compositor_thread_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&WebMediaPlayerMS::StartRenderingHelper, |
| + video_frame_provider_client_)); |
| +} |
| + |
| +void WebMediaPlayerMS::StopVideoFrameProviderAndWakeUpHelper( |
| + cc::VideoFrameProvider::Client* client, |
| + base::WaitableEvent* event) { |
| + client->StopUsingProvider(); |
| + event->Signal(); |
| +} |
| + |
| +void WebMediaPlayerMS::StopVideoFrameProviderHelper( |
| + cc::VideoFrameProvider::Client* client) { |
| + client->StopUsingProvider(); |
| +} |
| + |
| +void WebMediaPlayerMS::StartRenderingHelper( |
| + cc::VideoFrameProvider::Client* client) { |
| + client->StartRendering(); |
| +} |
| + |
| +void WebMediaPlayerMS::StopRenderingHelper( |
| + cc::VideoFrameProvider::Client* client) { |
| + client->StopRendering(); |
| } |
| bool WebMediaPlayerMS::UpdateCurrentFrame(base::TimeTicks deadline_min, |
| base::TimeTicks deadline_max) { |
| + TRACE_EVENT_BEGIN2("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", |
| + "Actual Render Begin", deadline_min.ToInternalValue(), |
| + "Actual Render End", deadline_max.ToInternalValue()); |
| + last_deadline_max_ = deadline_max; |
| + |
| // TODO(dalecurtis): This should make use of the deadline interval to ensure |
| // the painted frame is correct for the given interval. |
| - NOTREACHED(); |
| - return false; |
| + |
| + base::TimeTicks render_time; |
| + if (!current_frame_->metadata()->GetTimeTicks( |
| + media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { |
| + render_time = base::TimeTicks(); |
| + } |
| + TRACE_EVENT_END1("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", |
| + "Ideal Render Instant", render_time.ToInternalValue()); |
| + return !current_frame_used_; |
| } |
| bool WebMediaPlayerMS::HasCurrentFrame() { |
| @@ -483,6 +558,15 @@ void WebMediaPlayerMS::OnFrameAvailable( |
| const scoped_refptr<media::VideoFrame>& frame) { |
| DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable"; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| + |
| + base::TimeTicks render_time; |
| + if (!frame->metadata()->GetTimeTicks( |
| + media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { |
| + render_time = base::TimeTicks(); |
| + } |
| + TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable", |
| + "Ideal Render Instant", render_time.ToInternalValue()); |
| + |
| ++total_frame_count_; |
| if (!received_first_frame_) { |
| received_first_frame_ = true; |
| @@ -508,6 +592,16 @@ void WebMediaPlayerMS::OnFrameAvailable( |
| if (paused_) |
| return; |
| + if (base::TimeTicks::Now() > last_deadline_max_){ |
| + // TODO(qiangchen): Theoretically Now is between |
| + // [last_deadline_min_ - vsync_duration, last_deadline_min]. If Now is later |
| + // than last_deadline_max, it means UpdateCurrentFrame does not get called |
| + // for 2 vsyncs. A probable cause is that the video tag is invisible, but we |
| + // have to let old frames go (VRA::RemoveExpiredFrames), otherwise frames |
| + // will pile up, and when we use up all frame buffers, decoder will be |
| + // stuck. |
| + } |
| + |
| bool size_changed = !current_frame_.get() || |
| current_frame_->natural_size() != frame->natural_size(); |
| @@ -522,8 +616,6 @@ void WebMediaPlayerMS::OnFrameAvailable( |
| if (size_changed) |
| GetClient()->sizeChanged(); |
| - |
| - GetClient()->repaint(); |
| } |
| void WebMediaPlayerMS::RepaintInternal() { |