| 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 |