Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(291)

Side by Side Diff: media/blink/video_frame_compositor.cc

Issue 1083383005: Connect the new video rendering path to the compositor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@vra
Patch Set: Remove NullVideoSink Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "media/blink/video_frame_compositor.h" 5 #include "media/blink/video_frame_compositor.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h" 8 #include "base/message_loop/message_loop.h"
9 #include "base/time/default_tick_clock.h"
10 #include "base/trace_event/trace_event.h"
9 #include "media/base/video_frame.h" 11 #include "media/base/video_frame.h"
10 12
11 namespace media { 13 namespace media {
12 14
15 // The maximum time we'll allow to elapse between Render() callbacks if there is
16 // an external caller requesting frames via GetCurrentFrame(); i.e. there is a
17 // canvas which frames are being copied into.
18 static const int kStaleFrameThresholdMs = 250;
19
13 static bool IsOpaque(const scoped_refptr<VideoFrame>& frame) { 20 static bool IsOpaque(const scoped_refptr<VideoFrame>& frame) {
14 switch (frame->format()) { 21 switch (frame->format()) {
15 case VideoFrame::UNKNOWN: 22 case VideoFrame::UNKNOWN:
16 case VideoFrame::YV12: 23 case VideoFrame::YV12:
17 case VideoFrame::YV12J: 24 case VideoFrame::YV12J:
18 case VideoFrame::YV12HD: 25 case VideoFrame::YV12HD:
19 case VideoFrame::YV16: 26 case VideoFrame::YV16:
20 case VideoFrame::I420: 27 case VideoFrame::I420:
21 case VideoFrame::YV24: 28 case VideoFrame::YV24:
22 case VideoFrame::NV12: 29 case VideoFrame::NV12:
23 return true; 30 return true;
24 31
25 case VideoFrame::YV12A: 32 case VideoFrame::YV12A:
26 #if defined(VIDEO_HOLE) 33 #if defined(VIDEO_HOLE)
27 case VideoFrame::HOLE: 34 case VideoFrame::HOLE:
28 #endif // defined(VIDEO_HOLE) 35 #endif // defined(VIDEO_HOLE)
29 case VideoFrame::NATIVE_TEXTURE: 36 case VideoFrame::NATIVE_TEXTURE:
30 case VideoFrame::ARGB: 37 case VideoFrame::ARGB:
31 break; 38 break;
32 } 39 }
33 return false; 40 return false;
34 } 41 }
35 42
36 VideoFrameCompositor::VideoFrameCompositor( 43 VideoFrameCompositor::VideoFrameCompositor(
37 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner, 44 const scoped_refptr<base::SingleThreadTaskRunner>& compositor_task_runner,
38 const base::Callback<void(gfx::Size)>& natural_size_changed_cb, 45 const base::Callback<void(gfx::Size)>& natural_size_changed_cb,
39 const base::Callback<void(bool)>& opacity_changed_cb) 46 const base::Callback<void(bool)>& opacity_changed_cb)
40 : compositor_task_runner_(compositor_task_runner), 47 : compositor_task_runner_(compositor_task_runner),
48 tick_clock_(new base::DefaultTickClock()),
41 natural_size_changed_cb_(natural_size_changed_cb), 49 natural_size_changed_cb_(natural_size_changed_cb),
42 opacity_changed_cb_(opacity_changed_cb), 50 opacity_changed_cb_(opacity_changed_cb),
43 client_(nullptr), 51 client_(nullptr),
52 stale_frame_threshold_(
53 base::TimeDelta::FromMilliseconds(kStaleFrameThresholdMs)),
44 rendering_(false), 54 rendering_(false),
55 rendered_last_frame_(false),
45 callback_(nullptr) { 56 callback_(nullptr) {
46 } 57 }
47 58
48 VideoFrameCompositor::~VideoFrameCompositor() { 59 VideoFrameCompositor::~VideoFrameCompositor() {
49 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 60 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
50 DCHECK(!callback_); 61 DCHECK(!callback_);
51 DCHECK(!rendering_); 62 DCHECK(!rendering_);
52 if (client_) 63 if (client_)
53 client_->StopUsingProvider(); 64 client_->StopUsingProvider();
54 } 65 }
55 66
56 void VideoFrameCompositor::OnRendererStateUpdate() { 67 void VideoFrameCompositor::OnRendererStateUpdate(bool stop_if_not_rendering) {
57 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 68 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
58 if (!client_) 69 if (!client_)
59 return; 70 return;
60 71
61 base::AutoLock lock(lock_); 72 base::AutoLock lock(lock_);
62 if (callback_) { 73 if (callback_) {
63 if (rendering_) 74 if (rendering_)
64 client_->StartRendering(); 75 client_->StartRendering();
65 76 } else if (!rendering_ && stop_if_not_rendering) {
66 // TODO(dalecurtis): This will need to request the first frame so we have
67 // something to show, even if playback hasn't started yet.
68 } else if (rendering_) {
69 client_->StopRendering(); 77 client_->StopRendering();
70 } 78 }
71 } 79 }
72 80
73 scoped_refptr<VideoFrame> 81 scoped_refptr<VideoFrame>
74 VideoFrameCompositor::GetCurrentFrameAndUpdateIfStale() { 82 VideoFrameCompositor::GetCurrentFrameAndUpdateIfStale() {
75 // TODO(dalecurtis): Implement frame refresh when stale.
76 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 83 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
84 const base::TimeTicks now = tick_clock_->NowTicks();
85 if (now - last_frame_update_time_ > stale_frame_threshold_)
86 UpdateCurrentFrame(now, now + last_interval_);
87
77 return GetCurrentFrame(); 88 return GetCurrentFrame();
78 } 89 }
79 90
80 void VideoFrameCompositor::SetVideoFrameProviderClient( 91 void VideoFrameCompositor::SetVideoFrameProviderClient(
81 cc::VideoFrameProvider::Client* client) { 92 cc::VideoFrameProvider::Client* client) {
82 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 93 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
83 if (client_) 94 if (client_)
84 client_->StopUsingProvider(); 95 client_->StopUsingProvider();
85 client_ = client; 96 client_ = client;
86 OnRendererStateUpdate(); 97 OnRendererStateUpdate(false);
87 } 98 }
88 99
89 scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() { 100 scoped_refptr<VideoFrame> VideoFrameCompositor::GetCurrentFrame() {
90 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 101 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
91 return current_frame_; 102 return current_frame_;
92 } 103 }
93 104
94 void VideoFrameCompositor::PutCurrentFrame() { 105 void VideoFrameCompositor::PutCurrentFrame() {
95 DCHECK(compositor_task_runner_->BelongsToCurrentThread()); 106 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
96 // TODO(dalecurtis): Wire up a flag for RenderCallback::OnFrameDropped(). 107 rendered_last_frame_ = true;
97 } 108 }
98 109
99 bool VideoFrameCompositor::UpdateCurrentFrame(base::TimeTicks deadline_min, 110 bool VideoFrameCompositor::UpdateCurrentFrame(base::TimeTicks deadline_min,
100 base::TimeTicks deadline_max) { 111 base::TimeTicks deadline_max) {
101 // TODO(dalecurtis): Wire this up to RenderCallback::Render(). 112 DCHECK(compositor_task_runner_->BelongsToCurrentThread());
102 base::AutoLock lock(lock_); 113 base::AutoLock lock(lock_);
103 return false; 114 if (!callback_)
115 return false;
116
117 // If the previous frame was never rendered, let the client know.
118 if (!rendered_last_frame_ && current_frame_)
119 callback_->OnFrameDropped();
120
121 last_frame_update_time_ = tick_clock_->NowTicks();
122 last_interval_ = deadline_max - deadline_min;
123 scoped_refptr<VideoFrame> frame =
124 callback_->Render(deadline_min, deadline_max);
125
126 // Do nothing if the current frame has already been rendered.
127 if (current_frame_ == frame)
128 return false;
129
130 // Set the flag indicating that the current frame is unrendered, if we get a
131 // subsequent PutCurrentFrame() call it will mark it as rendered.
132 rendered_last_frame_ = false;
133
134 if (current_frame_.get() &&
135 current_frame_->natural_size() != frame->natural_size()) {
136 natural_size_changed_cb_.Run(frame->natural_size());
137 }
138
139 if (!current_frame_.get() || IsOpaque(current_frame_) != IsOpaque(frame)) {
140 opacity_changed_cb_.Run(IsOpaque(frame));
141 }
142
143 current_frame_ = frame;
144 return true;
104 } 145 }
105 146
106 void VideoFrameCompositor::Start(RenderCallback* callback) { 147 void VideoFrameCompositor::Start(RenderCallback* callback) {
107 NOTREACHED(); 148 TRACE_EVENT0("media", "VideoFrameCompositor::Start");
108
109 // Called from the media thread, so acquire the callback under lock before 149 // Called from the media thread, so acquire the callback under lock before
110 // returning in case a Stop() call comes in before the PostTask is processed. 150 // returning in case a Stop() call comes in before the PostTask is processed.
111 base::AutoLock lock(lock_); 151 base::AutoLock lock(lock_);
152 DCHECK(!rendering_);
153 DCHECK(!callback_);
154
112 callback_ = callback; 155 callback_ = callback;
113 rendering_ = true; 156 rendering_ = true;
157 current_frame_ = nullptr;
114 compositor_task_runner_->PostTask( 158 compositor_task_runner_->PostTask(
115 FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate, 159 FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate,
116 base::Unretained(this))); 160 base::Unretained(this), true));
117 } 161 }
118 162
119 void VideoFrameCompositor::Stop() { 163 void VideoFrameCompositor::Stop() {
120 NOTREACHED(); 164 TRACE_EVENT0("media", "VideoFrameCompositor::Stop");
121
122 // Called from the media thread, so release the callback under lock before 165 // Called from the media thread, so release the callback under lock before
123 // returning to avoid a pending UpdateCurrentFrame() call occurring before 166 // returning to avoid a pending UpdateCurrentFrame() call occurring before
124 // the PostTask is processed. 167 // the PostTask is processed.
125 base::AutoLock lock(lock_); 168 base::AutoLock lock(lock_);
169 DCHECK(rendering_);
170 DCHECK(callback_);
171
126 callback_ = nullptr; 172 callback_ = nullptr;
127 rendering_ = false; 173 rendering_ = false;
174 current_frame_ = nullptr;
128 compositor_task_runner_->PostTask( 175 compositor_task_runner_->PostTask(
129 FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate, 176 FROM_HERE, base::Bind(&VideoFrameCompositor::OnRendererStateUpdate,
130 base::Unretained(this))); 177 base::Unretained(this), true));
131 } 178 }
132 179
133 void VideoFrameCompositor::PaintFrameUsingOldRenderingPath( 180 void VideoFrameCompositor::PaintFrameUsingOldRenderingPath(
134 const scoped_refptr<VideoFrame>& frame) { 181 const scoped_refptr<VideoFrame>& frame) {
135 if (!compositor_task_runner_->BelongsToCurrentThread()) { 182 if (!compositor_task_runner_->BelongsToCurrentThread()) {
136 compositor_task_runner_->PostTask( 183 compositor_task_runner_->PostTask(
137 FROM_HERE, 184 FROM_HERE,
138 base::Bind(&VideoFrameCompositor::PaintFrameUsingOldRenderingPath, 185 base::Bind(&VideoFrameCompositor::PaintFrameUsingOldRenderingPath,
139 base::Unretained(this), frame)); 186 base::Unretained(this), frame));
140 return; 187 return;
141 } 188 }
142 189
143 if (current_frame_.get() && 190 if (current_frame_.get() &&
144 current_frame_->natural_size() != frame->natural_size()) { 191 current_frame_->natural_size() != frame->natural_size()) {
145 natural_size_changed_cb_.Run(frame->natural_size()); 192 natural_size_changed_cb_.Run(frame->natural_size());
146 } 193 }
147 194
148 if (!current_frame_.get() || IsOpaque(current_frame_) != IsOpaque(frame)) { 195 if (!current_frame_.get() || IsOpaque(current_frame_) != IsOpaque(frame)) {
149 opacity_changed_cb_.Run(IsOpaque(frame)); 196 opacity_changed_cb_.Run(IsOpaque(frame));
150 } 197 }
151 198
152 current_frame_ = frame; 199 current_frame_ = frame;
153 200
154 if (client_) 201 if (client_)
155 client_->DidReceiveFrame(); 202 client_->DidReceiveFrame();
156 } 203 }
157 204
158 } // namespace media 205 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698