diff options
Diffstat (limited to 'chromium/media/blink')
-rw-r--r-- | chromium/media/blink/video_frame_compositor.cc | 43 | ||||
-rw-r--r-- | chromium/media/blink/video_frame_compositor.h | 32 | ||||
-rw-r--r-- | chromium/media/blink/video_frame_compositor_unittest.cc | 37 | ||||
-rw-r--r-- | chromium/media/blink/watch_time_reporter_unittest.cc | 7 | ||||
-rw-r--r-- | chromium/media/blink/webmediaplayer_impl.cc | 52 | ||||
-rw-r--r-- | chromium/media/blink/webmediaplayer_impl.h | 8 |
6 files changed, 73 insertions, 106 deletions
diff --git a/chromium/media/blink/video_frame_compositor.cc b/chromium/media/blink/video_frame_compositor.cc index 8d162fc30c6..7abdf0999d8 100644 --- a/chromium/media/blink/video_frame_compositor.cc +++ b/chromium/media/blink/video_frame_compositor.cc @@ -134,6 +134,18 @@ scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() { return current_frame_; } +scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrameOnAnyThread() { + base::AutoLock lock(current_frame_lock_); + return current_frame_; +} + +void VideoFrameCompositor::SetCurrentFrame( + const scoped_refptr<VideoFrame>& frame) { + DCHECK(task_runner_->BelongsToCurrentThread()); + base::AutoLock lock(current_frame_lock_); + current_frame_ = frame; +} + void VideoFrameCompositor::PutCurrentFrame() { DCHECK(task_runner_->BelongsToCurrentThread()); rendered_last_frame_ = true; @@ -147,7 +159,7 @@ bool VideoFrameCompositor::UpdateCurrentFrame(base::TimeTicks deadline_min, bool VideoFrameCompositor::HasCurrentFrame() { DCHECK(task_runner_->BelongsToCurrentThread()); - return static_cast<bool>(current_frame_); + return static_cast<bool>(GetCurrentFrame()); } void VideoFrameCompositor::Start(RenderCallback* callback) { @@ -192,12 +204,11 @@ void VideoFrameCompositor::PaintSingleFrame( } } -scoped_refptr<VideoFrame> -VideoFrameCompositor::GetCurrentFrameAndUpdateIfStale() { +void VideoFrameCompositor::UpdateCurrentFrameIfStale() { DCHECK(task_runner_->BelongsToCurrentThread()); if (IsClientSinkAvailable() || !rendering_ || !is_background_rendering_) - return current_frame_; + return; DCHECK(!last_background_render_.is_null()); @@ -206,24 +217,12 @@ VideoFrameCompositor::GetCurrentFrameAndUpdateIfStale() { // Cap updates to 250Hz which should be more than enough for everyone. if (interval < base::TimeDelta::FromMilliseconds(4)) - return current_frame_; + return; // Update the interval based on the time between calls and call background // render which will give this information to the client. last_interval_ = interval; BackgroundRender(); - - return current_frame_; -} - -base::TimeDelta VideoFrameCompositor::GetCurrentFrameTimestamp() const { - // When the VFC is stopped, |callback_| is cleared; this synchronously - // prevents CallRender() from invoking ProcessNewFrame(), and so - // |current_frame_| won't change again until after Start(). (Assuming that - // PaintSingleFrame() is not also called while stopped.) - if (!current_frame_) - return base::TimeDelta(); - return current_frame_->timestamp(); } void VideoFrameCompositor::SetOnNewProcessedFrameCallback( @@ -237,8 +236,8 @@ bool VideoFrameCompositor::ProcessNewFrame( bool repaint_duplicate_frame) { DCHECK(task_runner_->BelongsToCurrentThread()); - if (frame && current_frame_ && !repaint_duplicate_frame && - frame->unique_id() == current_frame_->unique_id()) { + if (frame && GetCurrentFrame() && !repaint_duplicate_frame && + frame->unique_id() == GetCurrentFrame()->unique_id()) { return false; } @@ -246,7 +245,7 @@ bool VideoFrameCompositor::ProcessNewFrame( // subsequent PutCurrentFrame() call it will mark it as rendered. rendered_last_frame_ = false; - current_frame_ = frame; + SetCurrentFrame(frame); if (!new_processed_frame_cb_.is_null()) base::ResetAndReturn(&new_processed_frame_cb_).Run(base::TimeTicks::Now()); @@ -276,14 +275,14 @@ bool VideoFrameCompositor::CallRender(base::TimeTicks deadline_min, if (!callback_) { // Even if we no longer have a callback, return true if we have a frame // which |client_| hasn't seen before. - return !rendered_last_frame_ && current_frame_; + return !rendered_last_frame_ && GetCurrentFrame(); } DCHECK(rendering_); // If the previous frame was never rendered and we're not in background // rendering mode (nor have just exited it), let the client know. - if (!rendered_last_frame_ && current_frame_ && !background_rendering && + if (!rendered_last_frame_ && GetCurrentFrame() && !background_rendering && !is_background_rendering_) { callback_->OnFrameDropped(); } diff --git a/chromium/media/blink/video_frame_compositor.h b/chromium/media/blink/video_frame_compositor.h index 3a50d71aae0..46f66513d72 100644 --- a/chromium/media/blink/video_frame_compositor.h +++ b/chromium/media/blink/video_frame_compositor.h @@ -92,6 +92,12 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, scoped_refptr<VideoFrame> GetCurrentFrame() override; void PutCurrentFrame() override; + // Returns |current_frame_|, without offering a guarantee as to how recently + // it was updated. In certain applications, one might need to periodically + // call UpdateCurrentFrameIfStale on |task_runner_| to drive the updates. + // Can be called from any thread. + scoped_refptr<VideoFrame> GetCurrentFrameOnAnyThread(); + // VideoRendererSink implementation. These methods must be called from the // same thread (typically the media thread). void Start(RenderCallback* callback) override; @@ -99,24 +105,18 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, void PaintSingleFrame(const scoped_refptr<VideoFrame>& frame, bool repaint_duplicate_frame = false) override; - // Returns |current_frame_| if |client_| is set. If no |client_| is set, - // |is_background_rendering_| is true, and |callback_| is set, it requests a - // new frame from |callback_|, using the elapsed time between calls to this - // function as the render interval; defaulting to 16.6ms if no prior calls - // have been made. A cap of 250Hz (4ms) is in place to prevent clients from - // accidentally (or intentionally) spamming the rendering pipeline. + // If |client_| is not set, |callback_| is set, and |is_background_rendering_| + // is true, it requests a new frame from |callback_|. Uses the elapsed time + // between calls to this function as the render interval, defaulting to 16.6ms + // if no prior calls have been made. A cap of 250Hz (4ms) is in place to + // prevent clients from accidentally (or intentionally) spamming the rendering + // pipeline. // // This method is primarily to facilitate canvas and WebGL based applications // where the <video> tag is invisible (possibly not even in the DOM) and thus // does not receive a |client_|. In this case, frame acquisition is driven by // the frequency of canvas or WebGL paints requested via JavaScript. - scoped_refptr<VideoFrame> GetCurrentFrameAndUpdateIfStale(); - - // Returns the timestamp of the current (possibly stale) frame, or - // base::TimeDelta() if there is no current frame. This method may be called - // from the media thread as long as the VFC is stopped. (Assuming that - // PaintSingleFrame() is not also called while stopped.) - base::TimeDelta GetCurrentFrameTimestamp() const; + void UpdateCurrentFrameIfStale(); // Sets the callback to be run when the new frame has been processed. The // callback is only run once and then reset. @@ -156,6 +156,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, bool ProcessNewFrame(const scoped_refptr<VideoFrame>& frame, bool repaint_duplicate_frame); + void SetCurrentFrame(const scoped_refptr<VideoFrame>& frame); + // Called by |background_rendering_timer_| when enough time elapses where we // haven't seen a Render() call. void BackgroundRender(); @@ -193,8 +195,8 @@ class MEDIA_BLINK_EXPORT VideoFrameCompositor : public VideoRendererSink, base::TimeTicks last_background_render_; OnNewProcessedFrameCB new_processed_frame_cb_; - // These values are set on the compositor thread, but also read on the media - // thread when the VFC is stopped. + // Set on the compositor thread, but also read on the media thread. + base::Lock current_frame_lock_; scoped_refptr<VideoFrame> current_frame_; // These values are updated and read from the media and compositor threads. diff --git a/chromium/media/blink/video_frame_compositor_unittest.cc b/chromium/media/blink/video_frame_compositor_unittest.cc index 7f72e237db1..4e3d4748e47 100644 --- a/chromium/media/blink/video_frame_compositor_unittest.cc +++ b/chromium/media/blink/video_frame_compositor_unittest.cc @@ -246,33 +246,21 @@ TEST_P(VideoFrameCompositorTest, StopVideoRendererSink(true); } -TEST_P(VideoFrameCompositorTest, GetCurrentFrameAndUpdateIfStale) { +TEST_P(VideoFrameCompositorTest, UpdateCurrentFrameIfStale) { scoped_refptr<VideoFrame> opaque_frame_1 = CreateOpaqueFrame(); scoped_refptr<VideoFrame> opaque_frame_2 = CreateOpaqueFrame(); compositor_->set_background_rendering_for_testing(true); - // |current_frame_| should be null at this point since we don't have a client - // or a callback. - ASSERT_FALSE(compositor()->GetCurrentFrameAndUpdateIfStale()); - // Starting the video renderer should return a single frame. EXPECT_CALL(*this, Render(_, _, true)).WillOnce(Return(opaque_frame_1)); StartVideoRendererSink(); + EXPECT_EQ(opaque_frame_1, compositor()->GetCurrentFrame()); // Since we have a client, this call should not call background render, even // if a lot of time has elapsed between calls. tick_clock_->Advance(base::TimeDelta::FromSeconds(1)); - ASSERT_EQ(opaque_frame_1, compositor()->GetCurrentFrameAndUpdateIfStale()); - - // An update current frame call should stop background rendering. - EXPECT_CALL(*this, Render(_, _, false)).WillOnce(Return(opaque_frame_2)); - EXPECT_TRUE( - compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks())); - - // This call should still not call background render. - ASSERT_EQ(opaque_frame_2, compositor()->GetCurrentFrameAndUpdateIfStale()); - - testing::Mock::VerifyAndClearExpectations(this); + EXPECT_CALL(*this, Render(_, _, _)).Times(0); + compositor()->UpdateCurrentFrameIfStale(); if (IsSurfaceLayerForVideoEnabled()) { compositor()->set_submitter_for_test(nullptr); @@ -281,25 +269,24 @@ TEST_P(VideoFrameCompositorTest, GetCurrentFrameAndUpdateIfStale) { compositor()->SetVideoFrameProviderClient(nullptr); } - // This call should still not call background render, because we aren't in the - // background rendering state yet. - ASSERT_EQ(opaque_frame_2, compositor()->GetCurrentFrameAndUpdateIfStale()); - - // Wait for background rendering to tick again. + // Wait for background rendering to tick. base::RunLoop run_loop; EXPECT_CALL(*this, Render(_, _, true)) .WillOnce( - DoAll(RunClosure(run_loop.QuitClosure()), Return(opaque_frame_1))) - .WillOnce(Return(opaque_frame_2)); + DoAll(RunClosure(run_loop.QuitClosure()), Return(opaque_frame_2))); run_loop.Run(); // This call should still not call background render, because not enough time // has elapsed since the last background render call. - ASSERT_EQ(opaque_frame_1, compositor()->GetCurrentFrameAndUpdateIfStale()); + EXPECT_CALL(*this, Render(_, _, true)).Times(0); + compositor()->UpdateCurrentFrameIfStale(); + EXPECT_EQ(opaque_frame_2, compositor()->GetCurrentFrame()); // Advancing the tick clock should allow a new frame to be requested. tick_clock_->Advance(base::TimeDelta::FromMilliseconds(10)); - ASSERT_EQ(opaque_frame_2, compositor()->GetCurrentFrameAndUpdateIfStale()); + EXPECT_CALL(*this, Render(_, _, true)).WillOnce(Return(opaque_frame_1)); + compositor()->UpdateCurrentFrameIfStale(); + EXPECT_EQ(opaque_frame_1, compositor()->GetCurrentFrame()); // Background rendering should tick another render callback. StopVideoRendererSink(false); diff --git a/chromium/media/blink/watch_time_reporter_unittest.cc b/chromium/media/blink/watch_time_reporter_unittest.cc index 4f46e59a649..62e749d4bee 100644 --- a/chromium/media/blink/watch_time_reporter_unittest.cc +++ b/chromium/media/blink/watch_time_reporter_unittest.cc @@ -167,9 +167,10 @@ class WatchTimeReporterTest : public testing::TestWithParam<bool>, EXPECT_WATCH_TIME_FINALIZED(); wtr_.reset(new WatchTimeReporter( - mojom::PlaybackProperties::New( - kUnknownAudioCodec, kUnknownVideoCodec, has_audio, has_video_, - is_mse, is_encrypted, false, initial_video_size, url::Origin()), + mojom::PlaybackProperties::New(kUnknownAudioCodec, kUnknownVideoCodec, + has_audio, has_video_, is_mse, + is_encrypted, false, initial_video_size, + url::Origin(), true /* is_top_frame */), base::Bind(&WatchTimeReporterTest::GetCurrentMediaTime, base::Unretained(this)), this)); diff --git a/chromium/media/blink/webmediaplayer_impl.cc b/chromium/media/blink/webmediaplayer_impl.cc index 0c496c4f78c..5ee29f7682d 100644 --- a/chromium/media/blink/webmediaplayer_impl.cc +++ b/chromium/media/blink/webmediaplayer_impl.cc @@ -2206,48 +2206,23 @@ blink::WebAudioSourceProvider* WebMediaPlayerImpl::GetAudioSourceProvider() { return audio_source_provider_.get(); } -static void GetCurrentFrameAndSignal(VideoFrameCompositor* compositor, - scoped_refptr<VideoFrame>* video_frame_out, - base::WaitableEvent* event) { - TRACE_EVENT0("media", "GetCurrentFrameAndSignal"); - *video_frame_out = compositor->GetCurrentFrameAndUpdateIfStale(); - event->Signal(); -} - scoped_refptr<VideoFrame> WebMediaPlayerImpl::GetCurrentFrameFromCompositor() const { DCHECK(main_task_runner_->BelongsToCurrentThread()); TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor"); - // Needed when the |main_task_runner_| and |vfc_task_runner_| are the - // same to avoid deadlock in the Wait() below. - if (vfc_task_runner_->BelongsToCurrentThread()) { - scoped_refptr<VideoFrame> video_frame = - compositor_->GetCurrentFrameAndUpdateIfStale(); - if (!video_frame) { - return nullptr; - } - last_uploaded_frame_size_ = video_frame->natural_size(); - last_uploaded_frame_timestamp_ = video_frame->timestamp(); - return video_frame; - } + // Can be null. + scoped_refptr<VideoFrame> video_frame = + compositor_->GetCurrentFrameOnAnyThread(); - // Use a posted task and waitable event instead of a lock otherwise - // WebGL/Canvas can see different content than what the compositor is seeing. - scoped_refptr<VideoFrame> video_frame; - base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, - base::WaitableEvent::InitialState::NOT_SIGNALED); + // base::Unretained is safe here because |compositor_| is destroyed on + // |vfc_task_runner_|. The destruction is queued from |this|' destructor, + // which also runs on |main_task_runner_|, which makes it impossible for + // UpdateCurrentFrameIfStale() to be queued after |compositor_|'s dtor. vfc_task_runner_->PostTask( - FROM_HERE, - base::Bind(&GetCurrentFrameAndSignal, base::Unretained(compositor_.get()), - &video_frame, &event)); - event.Wait(); + FROM_HERE, base::Bind(&VideoFrameCompositor::UpdateCurrentFrameIfStale, + base::Unretained(compositor_.get()))); - if (!video_frame) { - return nullptr; - } - last_uploaded_frame_size_ = video_frame->natural_size(); - last_uploaded_frame_timestamp_ = video_frame->timestamp(); return video_frame; } @@ -2567,6 +2542,12 @@ void WebMediaPlayerImpl::CreateWatchTimeReporter() { if (!HasVideo() && !HasAudio()) return; + // URL is used for UKM reporting. Privacy requires we only report origin of + // the top frame. |is_top_frame| signals how to interpret the origin. + // TODO(crbug.com/787209): Stop getting origin from the renderer. + bool is_top_frame = frame_ == frame_->Top(); + url::Origin top_origin(frame_->Top()->GetSecurityOrigin()); + // Create the watch time reporter and synchronize its initial state. watch_time_reporter_.reset(new WatchTimeReporter( mojom::PlaybackProperties::New( @@ -2574,8 +2555,7 @@ void WebMediaPlayerImpl::CreateWatchTimeReporter() { pipeline_metadata_.video_decoder_config.codec(), pipeline_metadata_.has_audio, pipeline_metadata_.has_video, !!chunk_demuxer_, is_encrypted_, embedded_media_experience_enabled_, - pipeline_metadata_.natural_size, - url::Origin(frame_->GetSecurityOrigin())), + pipeline_metadata_.natural_size, top_origin, is_top_frame), base::BindRepeating(&WebMediaPlayerImpl::GetCurrentTimeInternal, base::Unretained(this)), watch_time_recorder_provider_)); diff --git a/chromium/media/blink/webmediaplayer_impl.h b/chromium/media/blink/webmediaplayer_impl.h index 56c5cf472d5..6f5e997ed4e 100644 --- a/chromium/media/blink/webmediaplayer_impl.h +++ b/chromium/media/blink/webmediaplayer_impl.h @@ -350,8 +350,9 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl void SetNetworkState(blink::WebMediaPlayer::NetworkState state); void SetReadyState(blink::WebMediaPlayer::ReadyState state); - // Returns the current video frame from |compositor_|. Blocks until the - // compositor can return the frame. + // Returns the current video frame from |compositor_|, and asks the compositor + // to update its frame if it is stale. + // Can return a nullptr. scoped_refptr<VideoFrame> GetCurrentFrameFromCompositor() const; // Called when the demuxer encounters encrypted streams. @@ -800,9 +801,6 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl // Whether the use of a surface layer instead of a video layer is enabled. bool surface_layer_for_video_enabled_ = false; - mutable gfx::Size last_uploaded_frame_size_; - mutable base::TimeDelta last_uploaded_frame_timestamp_; - base::CancelableCallback<void(base::TimeTicks)> frame_time_report_cb_; bool initial_video_height_recorded_ = false; |