Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/media/webmediaplayer_ms.h" | 5 #include "content/renderer/media/webmediaplayer_ms.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| 11 #include "base/message_loop/message_loop.h" | 11 #include "base/message_loop/message_loop.h" |
| 12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "cc/blink/context_provider_web_context.h" | 13 #include "cc/blink/context_provider_web_context.h" |
| 14 #include "cc/blink/web_layer_impl.h" | 14 #include "cc/blink/web_layer_impl.h" |
| 15 #include "cc/layers/video_frame_provider_client_impl.h" | |
| 15 #include "cc/layers/video_layer.h" | 16 #include "cc/layers/video_layer.h" |
| 16 #include "content/public/renderer/media_stream_audio_renderer.h" | 17 #include "content/public/renderer/media_stream_audio_renderer.h" |
| 17 #include "content/public/renderer/media_stream_renderer_factory.h" | 18 #include "content/public/renderer/media_stream_renderer_factory.h" |
| 18 #include "content/public/renderer/render_view.h" | 19 #include "content/public/renderer/render_view.h" |
| 19 #include "content/public/renderer/video_frame_provider.h" | 20 #include "content/public/renderer/video_frame_provider.h" |
| 20 #include "content/renderer/render_frame_impl.h" | 21 #include "content/renderer/render_frame_impl.h" |
| 21 #include "content/renderer/render_thread_impl.h" | 22 #include "content/renderer/render_thread_impl.h" |
| 22 #include "gpu/blink/webgraphicscontext3d_impl.h" | 23 #include "gpu/blink/webgraphicscontext3d_impl.h" |
| 23 #include "media/base/media_log.h" | 24 #include "media/base/media_log.h" |
| 24 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 return new_frame; | 87 return new_frame; |
| 87 } | 88 } |
| 88 | 89 |
| 89 } // anonymous namespace | 90 } // anonymous namespace |
| 90 | 91 |
| 91 WebMediaPlayerMS::WebMediaPlayerMS( | 92 WebMediaPlayerMS::WebMediaPlayerMS( |
| 92 blink::WebFrame* frame, | 93 blink::WebFrame* frame, |
| 93 blink::WebMediaPlayerClient* client, | 94 blink::WebMediaPlayerClient* client, |
| 94 base::WeakPtr<media::WebMediaPlayerDelegate> delegate, | 95 base::WeakPtr<media::WebMediaPlayerDelegate> delegate, |
| 95 media::MediaLog* media_log, | 96 media::MediaLog* media_log, |
| 96 scoped_ptr<MediaStreamRendererFactory> factory) | 97 scoped_ptr<MediaStreamRendererFactory> factory, |
| 98 scoped_refptr<base::SingleThreadTaskRunner> compositor_thread) | |
| 97 : frame_(frame), | 99 : frame_(frame), |
| 98 network_state_(WebMediaPlayer::NetworkStateEmpty), | 100 network_state_(WebMediaPlayer::NetworkStateEmpty), |
| 99 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 101 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 100 buffered_(static_cast<size_t>(0)), | 102 buffered_(static_cast<size_t>(0)), |
| 101 volume_(1.0f), | 103 volume_(1.0f), |
| 102 client_(client), | 104 client_(client), |
| 103 delegate_(delegate), | 105 delegate_(delegate), |
| 104 paused_(true), | 106 paused_(true), |
| 105 current_frame_used_(false), | 107 current_frame_used_(false), |
| 106 video_frame_provider_client_(NULL), | 108 video_frame_provider_client_(NULL), |
| 107 received_first_frame_(false), | 109 received_first_frame_(false), |
| 108 total_frame_count_(0), | 110 total_frame_count_(0), |
| 109 dropped_frame_count_(0), | 111 dropped_frame_count_(0), |
| 110 media_log_(media_log), | 112 media_log_(media_log), |
| 111 renderer_factory_(factory.Pass()) { | 113 renderer_factory_(factory.Pass()), |
| 114 compositor_thread_(compositor_thread), | |
| 115 wait_event_(false,false) { | |
| 112 DVLOG(1) << "WebMediaPlayerMS::ctor"; | 116 DVLOG(1) << "WebMediaPlayerMS::ctor"; |
| 113 media_log_->AddEvent( | 117 media_log_->AddEvent( |
| 114 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); | 118 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED)); |
| 115 } | 119 } |
| 116 | 120 |
| 117 WebMediaPlayerMS::~WebMediaPlayerMS() { | 121 WebMediaPlayerMS::~WebMediaPlayerMS() { |
| 118 DVLOG(1) << "WebMediaPlayerMS::dtor"; | 122 DVLOG(1) << "WebMediaPlayerMS::dtor"; |
| 119 DCHECK(thread_checker_.CalledOnValidThread()); | 123 DCHECK(thread_checker_.CalledOnValidThread()); |
| 120 | 124 |
| 121 SetVideoFrameProviderClient(NULL); | 125 // Wait till stop procedure finishes to avoid the case that after |
| 126 // WebMediaPlayerMS is destroyed, VideoFrameProvider is still trying to access | |
| 127 // it. | |
| 128 | |
| 129 if (video_frame_provider_client_){ | |
| 130 compositor_thread_->PostTask( | |
| 131 FROM_HERE, | |
| 132 base::Bind( | |
| 133 &WebMediaPlayerMS::StopVideoFrameProviderAndWakeUpHelper, | |
| 134 video_frame_provider_client_, | |
| 135 &wait_event_)); | |
| 136 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.
| |
| 137 } | |
| 138 | |
| 122 GetClient()->setWebLayer(NULL); | 139 GetClient()->setWebLayer(NULL); |
| 123 | 140 |
| 124 if (video_frame_provider_.get()) | 141 if (video_frame_provider_.get()) |
| 125 video_frame_provider_->Stop(); | 142 video_frame_provider_->Stop(); |
| 126 | 143 |
| 127 if (audio_renderer_.get()) | 144 if (audio_renderer_.get()) |
| 128 audio_renderer_->Stop(); | 145 audio_renderer_->Stop(); |
| 129 | 146 |
| 130 media_log_->AddEvent( | 147 media_log_->AddEvent( |
| 131 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); | 148 media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 } | 197 } |
| 181 | 198 |
| 182 void WebMediaPlayerMS::play() { | 199 void WebMediaPlayerMS::play() { |
| 183 DVLOG(1) << "WebMediaPlayerMS::play"; | 200 DVLOG(1) << "WebMediaPlayerMS::play"; |
| 184 DCHECK(thread_checker_.CalledOnValidThread()); | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 185 | 202 |
| 186 if (paused_) { | 203 if (paused_) { |
| 187 if (video_frame_provider_.get()) | 204 if (video_frame_provider_.get()) |
| 188 video_frame_provider_->Play(); | 205 video_frame_provider_->Play(); |
| 189 | 206 |
| 207 if (video_frame_provider_client_){ | |
| 208 compositor_thread_->PostTask( | |
| 209 FROM_HERE, | |
| 210 base::Bind(&WebMediaPlayerMS::StartRenderingHelper, | |
| 211 video_frame_provider_client_)); | |
| 212 } | |
| 213 | |
| 190 if (audio_renderer_.get()) | 214 if (audio_renderer_.get()) |
| 191 audio_renderer_->Play(); | 215 audio_renderer_->Play(); |
| 192 | 216 |
| 193 if (delegate_.get()) | 217 if (delegate_.get()) |
| 194 delegate_->DidPlay(this); | 218 delegate_->DidPlay(this); |
| 195 } | 219 } |
| 196 | 220 |
| 197 paused_ = false; | 221 paused_ = false; |
| 198 | 222 |
| 199 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); | 223 media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY)); |
| 200 } | 224 } |
| 201 | 225 |
| 202 void WebMediaPlayerMS::pause() { | 226 void WebMediaPlayerMS::pause() { |
| 203 DVLOG(1) << "WebMediaPlayerMS::pause"; | 227 DVLOG(1) << "WebMediaPlayerMS::pause"; |
| 204 DCHECK(thread_checker_.CalledOnValidThread()); | 228 DCHECK(thread_checker_.CalledOnValidThread()); |
| 205 | 229 |
| 206 if (video_frame_provider_.get()) | 230 if (video_frame_provider_.get()) |
| 207 video_frame_provider_->Pause(); | 231 video_frame_provider_->Pause(); |
| 208 | 232 |
| 233 if (video_frame_provider_client_){ | |
| 234 compositor_thread_->PostTask( | |
| 235 FROM_HERE, | |
| 236 base::Bind(&WebMediaPlayerMS::StopRenderingHelper, | |
| 237 video_frame_provider_client_)); | |
| 238 } | |
| 239 | |
| 209 if (!paused_) { | 240 if (!paused_) { |
| 210 if (audio_renderer_.get()) | 241 if (audio_renderer_.get()) |
| 211 audio_renderer_->Pause(); | 242 audio_renderer_->Pause(); |
| 212 | 243 |
| 213 if (delegate_.get()) | 244 if (delegate_.get()) |
| 214 delegate_->DidPause(this); | 245 delegate_->DidPause(this); |
| 215 } | 246 } |
| 216 | 247 |
| 217 paused_ = true; | 248 paused_ = true; |
| 218 | 249 |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 442 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha, | 473 gl, video_frame.get(), texture, internal_format, type, premultiply_alpha, |
| 443 flip_y); | 474 flip_y); |
| 444 return true; | 475 return true; |
| 445 } | 476 } |
| 446 | 477 |
| 447 void WebMediaPlayerMS::SetVideoFrameProviderClient( | 478 void WebMediaPlayerMS::SetVideoFrameProviderClient( |
| 448 cc::VideoFrameProvider::Client* client) { | 479 cc::VideoFrameProvider::Client* client) { |
| 449 // This is called from both the main renderer thread and the compositor | 480 // This is called from both the main renderer thread and the compositor |
| 450 // thread (when the main thread is blocked). | 481 // thread (when the main thread is blocked). |
| 451 if (video_frame_provider_client_) | 482 if (video_frame_provider_client_) |
| 452 video_frame_provider_client_->StopUsingProvider(); | 483 compositor_thread_->PostTask( |
| 484 FROM_HERE, | |
| 485 base::Bind( | |
| 486 &WebMediaPlayerMS::StopVideoFrameProviderHelper, | |
| 487 video_frame_provider_client_)); | |
| 488 | |
| 453 video_frame_provider_client_ = client; | 489 video_frame_provider_client_ = client; |
| 490 if (client && !paused_) | |
| 491 compositor_thread_->PostTask( | |
| 492 FROM_HERE, | |
| 493 base::Bind(&WebMediaPlayerMS::StartRenderingHelper, | |
| 494 video_frame_provider_client_)); | |
| 495 } | |
| 496 | |
| 497 void WebMediaPlayerMS::StopVideoFrameProviderAndWakeUpHelper( | |
| 498 cc::VideoFrameProvider::Client* client, | |
| 499 base::WaitableEvent* event) { | |
| 500 client->StopUsingProvider(); | |
| 501 event->Signal(); | |
| 502 } | |
| 503 | |
| 504 void WebMediaPlayerMS::StopVideoFrameProviderHelper( | |
| 505 cc::VideoFrameProvider::Client* client) { | |
| 506 client->StopUsingProvider(); | |
| 507 } | |
| 508 | |
| 509 void WebMediaPlayerMS::StartRenderingHelper( | |
| 510 cc::VideoFrameProvider::Client* client) { | |
| 511 client->StartRendering(); | |
| 512 } | |
| 513 | |
| 514 void WebMediaPlayerMS::StopRenderingHelper( | |
| 515 cc::VideoFrameProvider::Client* client) { | |
| 516 client->StopRendering(); | |
| 454 } | 517 } |
| 455 | 518 |
| 456 bool WebMediaPlayerMS::UpdateCurrentFrame(base::TimeTicks deadline_min, | 519 bool WebMediaPlayerMS::UpdateCurrentFrame(base::TimeTicks deadline_min, |
| 457 base::TimeTicks deadline_max) { | 520 base::TimeTicks deadline_max) { |
| 521 TRACE_EVENT_BEGIN2("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", | |
| 522 "Actual Render Begin", deadline_min.ToInternalValue(), | |
| 523 "Actual Render End", deadline_max.ToInternalValue()); | |
| 524 last_deadline_max_ = deadline_max; | |
| 525 | |
| 458 // TODO(dalecurtis): This should make use of the deadline interval to ensure | 526 // TODO(dalecurtis): This should make use of the deadline interval to ensure |
| 459 // the painted frame is correct for the given interval. | 527 // the painted frame is correct for the given interval. |
| 460 NOTREACHED(); | 528 |
| 461 return false; | 529 base::TimeTicks render_time; |
| 530 if (!current_frame_->metadata()->GetTimeTicks( | |
| 531 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { | |
| 532 render_time = base::TimeTicks(); | |
| 533 } | |
| 534 TRACE_EVENT_END1("webrtc", "WebMediaPlayerMS::UpdateCurrentFrame", | |
| 535 "Ideal Render Instant", render_time.ToInternalValue()); | |
| 536 return !current_frame_used_; | |
| 462 } | 537 } |
| 463 | 538 |
| 464 bool WebMediaPlayerMS::HasCurrentFrame() { | 539 bool WebMediaPlayerMS::HasCurrentFrame() { |
| 465 base::AutoLock auto_lock(current_frame_lock_); | 540 base::AutoLock auto_lock(current_frame_lock_); |
| 466 return current_frame_; | 541 return current_frame_; |
| 467 } | 542 } |
| 468 | 543 |
| 469 scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() { | 544 scoped_refptr<media::VideoFrame> WebMediaPlayerMS::GetCurrentFrame() { |
| 470 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame"; | 545 DVLOG(3) << "WebMediaPlayerMS::GetCurrentFrame"; |
| 471 base::AutoLock auto_lock(current_frame_lock_); | 546 base::AutoLock auto_lock(current_frame_lock_); |
| 472 if (!current_frame_.get()) | 547 if (!current_frame_.get()) |
| 473 return NULL; | 548 return NULL; |
| 474 current_frame_used_ = true; | 549 current_frame_used_ = true; |
| 475 return current_frame_; | 550 return current_frame_; |
| 476 } | 551 } |
| 477 | 552 |
| 478 void WebMediaPlayerMS::PutCurrentFrame() { | 553 void WebMediaPlayerMS::PutCurrentFrame() { |
| 479 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame"; | 554 DVLOG(3) << "WebMediaPlayerMS::PutCurrentFrame"; |
| 480 } | 555 } |
| 481 | 556 |
| 482 void WebMediaPlayerMS::OnFrameAvailable( | 557 void WebMediaPlayerMS::OnFrameAvailable( |
| 483 const scoped_refptr<media::VideoFrame>& frame) { | 558 const scoped_refptr<media::VideoFrame>& frame) { |
| 484 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable"; | 559 DVLOG(3) << "WebMediaPlayerMS::OnFrameAvailable"; |
| 485 DCHECK(thread_checker_.CalledOnValidThread()); | 560 DCHECK(thread_checker_.CalledOnValidThread()); |
| 561 | |
| 562 base::TimeTicks render_time; | |
| 563 if (!frame->metadata()->GetTimeTicks( | |
| 564 media::VideoFrameMetadata::REFERENCE_TIME, &render_time)) { | |
| 565 render_time = base::TimeTicks(); | |
| 566 } | |
| 567 TRACE_EVENT1("webrtc", "WebMediaPlayerMS::OnFrameAvailable", | |
| 568 "Ideal Render Instant", render_time.ToInternalValue()); | |
| 569 | |
| 486 ++total_frame_count_; | 570 ++total_frame_count_; |
| 487 if (!received_first_frame_) { | 571 if (!received_first_frame_) { |
| 488 received_first_frame_ = true; | 572 received_first_frame_ = true; |
| 489 { | 573 { |
| 490 base::AutoLock auto_lock(current_frame_lock_); | 574 base::AutoLock auto_lock(current_frame_lock_); |
| 491 DCHECK(!current_frame_used_); | 575 DCHECK(!current_frame_used_); |
| 492 current_frame_ = frame; | 576 current_frame_ = frame; |
| 493 } | 577 } |
| 494 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 578 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 495 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 579 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 496 GetClient()->sizeChanged(); | 580 GetClient()->sizeChanged(); |
| 497 | 581 |
| 498 if (video_frame_provider_.get()) { | 582 if (video_frame_provider_.get()) { |
| 499 video_weblayer_.reset(new cc_blink::WebLayerImpl( | 583 video_weblayer_.reset(new cc_blink::WebLayerImpl( |
| 500 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(), this, | 584 cc::VideoLayer::Create(cc_blink::WebLayerImpl::LayerSettings(), this, |
| 501 media::VIDEO_ROTATION_0))); | 585 media::VIDEO_ROTATION_0))); |
| 502 video_weblayer_->setOpaque(true); | 586 video_weblayer_->setOpaque(true); |
| 503 GetClient()->setWebLayer(video_weblayer_.get()); | 587 GetClient()->setWebLayer(video_weblayer_.get()); |
| 504 } | 588 } |
| 505 } | 589 } |
| 506 | 590 |
| 507 // Do not update |current_frame_| when paused. | 591 // Do not update |current_frame_| when paused. |
| 508 if (paused_) | 592 if (paused_) |
| 509 return; | 593 return; |
| 510 | 594 |
| 595 if (base::TimeTicks::Now() > last_deadline_max_){ | |
| 596 // TODO(qiangchen): Theoretically Now is between | |
| 597 // [last_deadline_min_ - vsync_duration, last_deadline_min]. If Now is later | |
| 598 // than last_deadline_max, it means UpdateCurrentFrame does not get called | |
| 599 // for 2 vsyncs. A probable cause is that the video tag is invisible, but we | |
| 600 // have to let old frames go (VRA::RemoveExpiredFrames), otherwise frames | |
| 601 // will pile up, and when we use up all frame buffers, decoder will be | |
| 602 // stuck. | |
| 603 } | |
| 604 | |
| 511 bool size_changed = !current_frame_.get() || | 605 bool size_changed = !current_frame_.get() || |
| 512 current_frame_->natural_size() != frame->natural_size(); | 606 current_frame_->natural_size() != frame->natural_size(); |
| 513 | 607 |
| 514 { | 608 { |
| 515 base::AutoLock auto_lock(current_frame_lock_); | 609 base::AutoLock auto_lock(current_frame_lock_); |
| 516 if (!current_frame_used_ && current_frame_.get()) | 610 if (!current_frame_used_ && current_frame_.get()) |
| 517 ++dropped_frame_count_; | 611 ++dropped_frame_count_; |
| 518 current_frame_ = frame; | 612 current_frame_ = frame; |
| 519 current_time_ = frame->timestamp(); | 613 current_time_ = frame->timestamp(); |
| 520 current_frame_used_ = false; | 614 current_frame_used_ = false; |
| 521 } | 615 } |
| 522 | 616 |
| 523 if (size_changed) | 617 if (size_changed) |
| 524 GetClient()->sizeChanged(); | 618 GetClient()->sizeChanged(); |
| 525 | |
| 526 GetClient()->repaint(); | |
| 527 } | 619 } |
| 528 | 620 |
| 529 void WebMediaPlayerMS::RepaintInternal() { | 621 void WebMediaPlayerMS::RepaintInternal() { |
| 530 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal"; | 622 DVLOG(1) << "WebMediaPlayerMS::RepaintInternal"; |
| 531 DCHECK(thread_checker_.CalledOnValidThread()); | 623 DCHECK(thread_checker_.CalledOnValidThread()); |
| 532 GetClient()->repaint(); | 624 GetClient()->repaint(); |
| 533 } | 625 } |
| 534 | 626 |
| 535 void WebMediaPlayerMS::OnSourceError() { | 627 void WebMediaPlayerMS::OnSourceError() { |
| 536 DVLOG(1) << "WebMediaPlayerMS::OnSourceError"; | 628 DVLOG(1) << "WebMediaPlayerMS::OnSourceError"; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 553 GetClient()->readyStateChanged(); | 645 GetClient()->readyStateChanged(); |
| 554 } | 646 } |
| 555 | 647 |
| 556 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() { | 648 blink::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() { |
| 557 DCHECK(thread_checker_.CalledOnValidThread()); | 649 DCHECK(thread_checker_.CalledOnValidThread()); |
| 558 DCHECK(client_); | 650 DCHECK(client_); |
| 559 return client_; | 651 return client_; |
| 560 } | 652 } |
| 561 | 653 |
| 562 } // namespace content | 654 } // namespace content |
| OLD | NEW |