OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/capture_video_decoder.h" | 5 #include "content/renderer/media/capture_video_decoder.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "content/renderer/media/video_capture_impl_manager.h" | 8 #include "content/renderer/media/video_capture_impl_manager.h" |
9 #include "media/base/filter_host.h" | 9 #include "media/base/filter_host.h" |
10 #include "media/base/limits.h" | 10 #include "media/base/limits.h" |
11 #include "media/base/video_util.h" | 11 #include "media/base/video_util.h" |
12 | 12 |
13 using media::CopyYPlane; | 13 using media::CopyYPlane; |
14 using media::CopyUPlane; | 14 using media::CopyUPlane; |
15 using media::CopyVPlane; | 15 using media::CopyVPlane; |
16 | 16 |
17 CaptureVideoDecoder::CaptureVideoDecoder( | 17 CaptureVideoDecoder::CaptureVideoDecoder( |
18 base::MessageLoopProxy* message_loop_proxy, | 18 base::MessageLoopProxy* message_loop_proxy, |
19 media::VideoCaptureSessionId video_stream_id, | 19 media::VideoCaptureSessionId video_stream_id, |
20 VideoCaptureImplManager* vc_manager, | 20 VideoCaptureImplManager* vc_manager, |
21 const media::VideoCapture::VideoCaptureCapability& capability) | 21 const media::VideoCapture::VideoCaptureCapability& capability) |
22 : message_loop_proxy_(message_loop_proxy), | 22 : message_loop_proxy_(message_loop_proxy), |
23 vc_manager_(vc_manager), | 23 vc_manager_(vc_manager), |
24 capability_(capability), | 24 capability_(capability), |
| 25 natural_size_(capability.width, capability.height), |
25 state_(kUnInitialized), | 26 state_(kUnInitialized), |
26 video_stream_id_(video_stream_id), | 27 video_stream_id_(video_stream_id), |
27 capture_engine_(NULL) { | 28 capture_engine_(NULL) { |
28 DCHECK(vc_manager); | 29 DCHECK(vc_manager); |
29 } | 30 } |
30 | 31 |
31 CaptureVideoDecoder::~CaptureVideoDecoder() {} | 32 CaptureVideoDecoder::~CaptureVideoDecoder() {} |
32 | 33 |
33 void CaptureVideoDecoder::Initialize( | 34 void CaptureVideoDecoder::Initialize( |
34 media::DemuxerStream* demuxer_stream, | 35 media::DemuxerStream* demuxer_stream, |
35 const base::Closure& filter_callback, | 36 const base::Closure& filter_callback, |
36 const media::StatisticsCallback& stat_callback) { | 37 const media::StatisticsCallback& stat_callback) { |
37 message_loop_proxy_->PostTask( | 38 message_loop_proxy_->PostTask( |
38 FROM_HERE, | 39 FROM_HERE, |
39 base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, | 40 base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, |
40 this, make_scoped_refptr(demuxer_stream), | 41 this, make_scoped_refptr(demuxer_stream), |
41 filter_callback, stat_callback)); | 42 filter_callback, stat_callback)); |
42 } | 43 } |
43 | 44 |
44 void CaptureVideoDecoder::ProduceVideoFrame( | 45 void CaptureVideoDecoder::Read(const ReadCB& callback) { |
45 scoped_refptr<media::VideoFrame> video_frame) { | |
46 message_loop_proxy_->PostTask( | 46 message_loop_proxy_->PostTask( |
47 FROM_HERE, | 47 FROM_HERE, |
48 base::Bind(&CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread, | 48 base::Bind(&CaptureVideoDecoder::ReadOnDecoderThread, |
49 this, video_frame)); | 49 this, callback)); |
50 } | 50 } |
51 | 51 |
52 gfx::Size CaptureVideoDecoder::natural_size() { | 52 const gfx::Size& CaptureVideoDecoder::natural_size() { |
53 return gfx::Size(capability_.width, capability_.height); | 53 return natural_size_; |
54 } | 54 } |
55 | 55 |
56 void CaptureVideoDecoder::Play(const base::Closure& callback) { | 56 void CaptureVideoDecoder::Play(const base::Closure& callback) { |
57 message_loop_proxy_->PostTask( | 57 message_loop_proxy_->PostTask( |
58 FROM_HERE, | 58 FROM_HERE, |
59 base::Bind(&CaptureVideoDecoder::PlayOnDecoderThread, | 59 base::Bind(&CaptureVideoDecoder::PlayOnDecoderThread, |
60 this, callback)); | 60 this, callback)); |
61 } | 61 } |
62 | 62 |
63 void CaptureVideoDecoder::Pause(const base::Closure& callback) { | 63 void CaptureVideoDecoder::Pause(const base::Closure& callback) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 | 124 |
125 void CaptureVideoDecoder::InitializeOnDecoderThread( | 125 void CaptureVideoDecoder::InitializeOnDecoderThread( |
126 media::DemuxerStream* demuxer_stream, | 126 media::DemuxerStream* demuxer_stream, |
127 const base::Closure& filter_callback, | 127 const base::Closure& filter_callback, |
128 const media::StatisticsCallback& stat_callback) { | 128 const media::StatisticsCallback& stat_callback) { |
129 VLOG(1) << "InitializeOnDecoderThread."; | 129 VLOG(1) << "InitializeOnDecoderThread."; |
130 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 130 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
131 | 131 |
132 capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); | 132 capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); |
133 | 133 |
134 available_frames_.clear(); | |
135 | |
136 statistics_callback_ = stat_callback; | 134 statistics_callback_ = stat_callback; |
137 filter_callback.Run(); | 135 filter_callback.Run(); |
138 state_ = kNormal; | 136 state_ = kNormal; |
139 } | 137 } |
140 | 138 |
141 void CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread( | 139 void CaptureVideoDecoder::ReadOnDecoderThread(const ReadCB& callback) { |
142 scoped_refptr<media::VideoFrame> video_frame) { | |
143 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 140 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
144 available_frames_.push_back(video_frame); | 141 CHECK(read_cb_.is_null()); |
| 142 read_cb_ = callback; |
145 } | 143 } |
146 | 144 |
147 void CaptureVideoDecoder::PlayOnDecoderThread(const base::Closure& callback) { | 145 void CaptureVideoDecoder::PlayOnDecoderThread(const base::Closure& callback) { |
148 VLOG(1) << "PlayOnDecoderThread."; | 146 VLOG(1) << "PlayOnDecoderThread."; |
149 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 147 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
150 callback.Run(); | 148 callback.Run(); |
151 } | 149 } |
152 | 150 |
153 void CaptureVideoDecoder::PauseOnDecoderThread(const base::Closure& callback) { | 151 void CaptureVideoDecoder::PauseOnDecoderThread(const base::Closure& callback) { |
154 VLOG(1) << "PauseOnDecoderThread."; | 152 VLOG(1) << "PauseOnDecoderThread."; |
155 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 153 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
156 state_ = kPaused; | 154 state_ = kPaused; |
157 media::VideoDecoder::Pause(callback); | 155 media::VideoDecoder::Pause(callback); |
158 } | 156 } |
159 | 157 |
160 void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& callback) { | 158 void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& callback) { |
161 VLOG(1) << "StopOnDecoderThread."; | 159 VLOG(1) << "StopOnDecoderThread."; |
162 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 160 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
163 pending_stop_cb_ = callback; | 161 pending_stop_cb_ = callback; |
164 state_ = kStopped; | 162 state_ = kStopped; |
165 capture_engine_->StopCapture(this); | 163 capture_engine_->StopCapture(this); |
166 } | 164 } |
167 | 165 |
168 void CaptureVideoDecoder::SeekOnDecoderThread(base::TimeDelta time, | 166 void CaptureVideoDecoder::SeekOnDecoderThread(base::TimeDelta time, |
169 const media::FilterStatusCB& cb) { | 167 const media::FilterStatusCB& cb) { |
170 VLOG(1) << "SeekOnDecoderThread."; | 168 VLOG(1) << "SeekOnDecoderThread."; |
171 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 169 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
172 | 170 |
173 state_ = kSeeking; | |
174 // Create output buffer pool and pass the frames to renderer | |
175 // so that the renderer can complete the seeking | |
176 for (size_t i = 0; i < media::Limits::kMaxVideoFrames; ++i) { | |
177 VideoFrameReady(media::VideoFrame::CreateBlackFrame(capability_.width, | |
178 capability_.height)); | |
179 } | |
180 | |
181 cb.Run(media::PIPELINE_OK); | 171 cb.Run(media::PIPELINE_OK); |
182 state_ = kNormal; | 172 state_ = kNormal; |
183 capture_engine_->StartCapture(this, capability_); | 173 capture_engine_->StartCapture(this, capability_); |
184 } | 174 } |
185 | 175 |
186 void CaptureVideoDecoder::OnStoppedOnDecoderThread( | 176 void CaptureVideoDecoder::OnStoppedOnDecoderThread( |
187 media::VideoCapture* capture) { | 177 media::VideoCapture* capture) { |
188 VLOG(1) << "OnStoppedOnDecoderThread."; | 178 VLOG(1) << "OnStoppedOnDecoderThread."; |
189 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 179 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
190 if (!pending_stop_cb_.is_null()) | 180 if (!pending_stop_cb_.is_null()) |
191 media::ResetAndRunCB(&pending_stop_cb_); | 181 media::ResetAndRunCB(&pending_stop_cb_); |
192 vc_manager_->RemoveDevice(video_stream_id_, this); | 182 vc_manager_->RemoveDevice(video_stream_id_, this); |
193 } | 183 } |
194 | 184 |
195 void CaptureVideoDecoder::OnBufferReadyOnDecoderThread( | 185 void CaptureVideoDecoder::OnBufferReadyOnDecoderThread( |
196 media::VideoCapture* capture, | 186 media::VideoCapture* capture, |
197 scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { | 187 scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { |
198 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 188 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
199 | 189 |
200 if (available_frames_.size() == 0 || kNormal != state_) { | 190 if (read_cb_.is_null() || kNormal != state_) { |
201 capture->FeedBuffer(buf); | 191 capture->FeedBuffer(buf); |
202 return; | 192 return; |
203 } | 193 } |
204 | 194 |
205 scoped_refptr<media::VideoFrame> video_frame = available_frames_.front(); | |
206 available_frames_.pop_front(); | |
207 | |
208 if (buf->width != capability_.width || buf->height != capability_.height) { | 195 if (buf->width != capability_.width || buf->height != capability_.height) { |
209 capability_.width = buf->width; | 196 capability_.width = buf->width; |
210 capability_.height = buf->height; | 197 capability_.height = buf->height; |
211 host()->SetNaturalVideoSize( | 198 natural_size_.SetSize(buf->width, buf->height); |
212 gfx::Size(capability_.width, capability_.height)); | 199 host()->SetNaturalVideoSize(natural_size_); |
213 } | 200 } |
214 | 201 |
215 // Check if there's a size change. | 202 // Always allocate a new frame. |
216 if (static_cast<int>(video_frame->width()) != capability_.width || | 203 // |
217 static_cast<int>(video_frame->height()) != capability_.height) { | 204 // TODO(scherkus): migrate this to proper buffer recycling. |
218 // Allocate new buffer based on the new size. | 205 scoped_refptr<media::VideoFrame> video_frame = |
219 video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, | 206 media::VideoFrame::CreateFrame(media::VideoFrame::YV12, |
220 capability_.width, | 207 natural_size_.width(), |
221 capability_.height, | 208 natural_size_.height(), |
222 media::kNoTimestamp, | 209 buf->timestamp - start_time_, |
223 media::kNoTimestamp); | 210 base::TimeDelta::FromMilliseconds(33)); |
224 } | |
225 | |
226 video_frame->SetTimestamp(buf->timestamp - start_time_); | |
227 video_frame->SetDuration(base::TimeDelta::FromMilliseconds(33)); | |
228 | 211 |
229 uint8* buffer = buf->memory_pointer; | 212 uint8* buffer = buf->memory_pointer; |
230 | 213 |
231 // Assume YV12 format. | 214 // Assume YV12 format. |
232 // TODO(vrk): This DCHECK fails in content_unittests ... it should not! | 215 // TODO(vrk): This DCHECK fails in content_unittests ... it should not! |
233 // DCHECK(capability_.raw_type == media::VideoFrame::YV12); | 216 // DCHECK(capability_.raw_type == media::VideoFrame::YV12); |
234 int y_width = capability_.width; | 217 int y_width = capability_.width; |
235 int y_height = capability_.height; | 218 int y_height = capability_.height; |
236 int uv_width = capability_.width / 2; | 219 int uv_width = capability_.width / 2; |
237 int uv_height = capability_.height / 2; // YV12 format. | 220 int uv_height = capability_.height / 2; // YV12 format. |
238 CopyYPlane(buffer, y_width, y_height, video_frame); | 221 CopyYPlane(buffer, y_width, y_height, video_frame); |
239 buffer += y_width * y_height; | 222 buffer += y_width * y_height; |
240 CopyUPlane(buffer, uv_width, uv_height, video_frame); | 223 CopyUPlane(buffer, uv_width, uv_height, video_frame); |
241 buffer += uv_width * uv_height; | 224 buffer += uv_width * uv_height; |
242 CopyVPlane(buffer, uv_width, uv_height, video_frame); | 225 CopyVPlane(buffer, uv_width, uv_height, video_frame); |
243 | 226 |
244 VideoFrameReady(video_frame); | 227 DeliverFrame(video_frame); |
245 capture->FeedBuffer(buf); | 228 capture->FeedBuffer(buf); |
246 } | 229 } |
| 230 |
| 231 void CaptureVideoDecoder::DeliverFrame( |
| 232 const scoped_refptr<media::VideoFrame>& video_frame) { |
| 233 // Reset the callback before running to protect against reentrancy. |
| 234 ReadCB read_cb = read_cb_; |
| 235 read_cb_.Reset(); |
| 236 read_cb.Run(video_frame); |
| 237 } |
OLD | NEW |