| 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" |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 media::DemuxerStream* demuxer_stream, | 34 media::DemuxerStream* demuxer_stream, |
| 35 const base::Closure& filter_callback, | 35 const base::Closure& filter_callback, |
| 36 const media::StatisticsCallback& stat_callback) { | 36 const media::StatisticsCallback& stat_callback) { |
| 37 message_loop_proxy_->PostTask( | 37 message_loop_proxy_->PostTask( |
| 38 FROM_HERE, | 38 FROM_HERE, |
| 39 base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, | 39 base::Bind(&CaptureVideoDecoder::InitializeOnDecoderThread, |
| 40 this, make_scoped_refptr(demuxer_stream), | 40 this, make_scoped_refptr(demuxer_stream), |
| 41 filter_callback, stat_callback)); | 41 filter_callback, stat_callback)); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void CaptureVideoDecoder::ProduceVideoFrame( | 44 void CaptureVideoDecoder::Read(const FrameReadyCB& callback) { |
| 45 scoped_refptr<media::VideoFrame> video_frame) { | |
| 46 message_loop_proxy_->PostTask( | 45 message_loop_proxy_->PostTask( |
| 47 FROM_HERE, | 46 FROM_HERE, |
| 48 base::Bind(&CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread, | 47 base::Bind(&CaptureVideoDecoder::ReadOnDecoderThread, |
| 49 this, video_frame)); | 48 this, callback)); |
| 50 } | 49 } |
| 51 | 50 |
| 52 gfx::Size CaptureVideoDecoder::natural_size() { | 51 gfx::Size CaptureVideoDecoder::natural_size() { |
| 53 return gfx::Size(capability_.width, capability_.height); | 52 return gfx::Size(capability_.width, capability_.height); |
| 54 } | 53 } |
| 55 | 54 |
| 56 void CaptureVideoDecoder::Play(const base::Closure& callback) { | 55 void CaptureVideoDecoder::Play(const base::Closure& callback) { |
| 57 message_loop_proxy_->PostTask( | 56 message_loop_proxy_->PostTask( |
| 58 FROM_HERE, | 57 FROM_HERE, |
| 59 base::Bind(&CaptureVideoDecoder::PlayOnDecoderThread, | 58 base::Bind(&CaptureVideoDecoder::PlayOnDecoderThread, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 | 123 |
| 125 void CaptureVideoDecoder::InitializeOnDecoderThread( | 124 void CaptureVideoDecoder::InitializeOnDecoderThread( |
| 126 media::DemuxerStream* demuxer_stream, | 125 media::DemuxerStream* demuxer_stream, |
| 127 const base::Closure& filter_callback, | 126 const base::Closure& filter_callback, |
| 128 const media::StatisticsCallback& stat_callback) { | 127 const media::StatisticsCallback& stat_callback) { |
| 129 VLOG(1) << "InitializeOnDecoderThread."; | 128 VLOG(1) << "InitializeOnDecoderThread."; |
| 130 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 129 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 131 | 130 |
| 132 capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); | 131 capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this); |
| 133 | 132 |
| 134 available_frames_.clear(); | |
| 135 | |
| 136 statistics_callback_ = stat_callback; | 133 statistics_callback_ = stat_callback; |
| 137 filter_callback.Run(); | 134 filter_callback.Run(); |
| 138 state_ = kNormal; | 135 state_ = kNormal; |
| 139 } | 136 } |
| 140 | 137 |
| 141 void CaptureVideoDecoder::ProduceVideoFrameOnDecoderThread( | 138 void CaptureVideoDecoder::ReadOnDecoderThread(const FrameReadyCB& callback) { |
| 142 scoped_refptr<media::VideoFrame> video_frame) { | |
| 143 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 139 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 144 available_frames_.push_back(video_frame); | 140 CHECK(frame_ready_cb_.is_null()); |
| 141 frame_ready_cb_ = callback; |
| 145 } | 142 } |
| 146 | 143 |
| 147 void CaptureVideoDecoder::PlayOnDecoderThread(const base::Closure& callback) { | 144 void CaptureVideoDecoder::PlayOnDecoderThread(const base::Closure& callback) { |
| 148 VLOG(1) << "PlayOnDecoderThread."; | 145 VLOG(1) << "PlayOnDecoderThread."; |
| 149 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 146 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 150 callback.Run(); | 147 callback.Run(); |
| 151 } | 148 } |
| 152 | 149 |
| 153 void CaptureVideoDecoder::PauseOnDecoderThread(const base::Closure& callback) { | 150 void CaptureVideoDecoder::PauseOnDecoderThread(const base::Closure& callback) { |
| 154 VLOG(1) << "PauseOnDecoderThread."; | 151 VLOG(1) << "PauseOnDecoderThread."; |
| 155 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 152 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 156 state_ = kPaused; | 153 state_ = kPaused; |
| 157 media::VideoDecoder::Pause(callback); | 154 media::VideoDecoder::Pause(callback); |
| 158 } | 155 } |
| 159 | 156 |
| 160 void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& callback) { | 157 void CaptureVideoDecoder::StopOnDecoderThread(const base::Closure& callback) { |
| 161 VLOG(1) << "StopOnDecoderThread."; | 158 VLOG(1) << "StopOnDecoderThread."; |
| 162 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 159 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 163 pending_stop_cb_ = callback; | 160 pending_stop_cb_ = callback; |
| 164 state_ = kStopped; | 161 state_ = kStopped; |
| 165 capture_engine_->StopCapture(this); | 162 capture_engine_->StopCapture(this); |
| 166 } | 163 } |
| 167 | 164 |
| 168 void CaptureVideoDecoder::SeekOnDecoderThread(base::TimeDelta time, | 165 void CaptureVideoDecoder::SeekOnDecoderThread(base::TimeDelta time, |
| 169 const media::FilterStatusCB& cb) { | 166 const media::FilterStatusCB& cb) { |
| 170 VLOG(1) << "SeekOnDecoderThread."; | 167 VLOG(1) << "SeekOnDecoderThread."; |
| 171 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 168 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 172 | 169 |
| 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); | |
| 182 state_ = kNormal; | 170 state_ = kNormal; |
| 183 capture_engine_->StartCapture(this, capability_); | 171 capture_engine_->StartCapture(this, capability_); |
| 184 } | 172 } |
| 185 | 173 |
| 186 void CaptureVideoDecoder::OnStoppedOnDecoderThread( | 174 void CaptureVideoDecoder::OnStoppedOnDecoderThread( |
| 187 media::VideoCapture* capture) { | 175 media::VideoCapture* capture) { |
| 188 VLOG(1) << "OnStoppedOnDecoderThread."; | 176 VLOG(1) << "OnStoppedOnDecoderThread."; |
| 189 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 177 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 190 if (!pending_stop_cb_.is_null()) | 178 if (!pending_stop_cb_.is_null()) |
| 191 media::ResetAndRunCB(&pending_stop_cb_); | 179 media::ResetAndRunCB(&pending_stop_cb_); |
| 192 vc_manager_->RemoveDevice(video_stream_id_, this); | 180 vc_manager_->RemoveDevice(video_stream_id_, this); |
| 193 } | 181 } |
| 194 | 182 |
| 195 void CaptureVideoDecoder::OnBufferReadyOnDecoderThread( | 183 void CaptureVideoDecoder::OnBufferReadyOnDecoderThread( |
| 196 media::VideoCapture* capture, | 184 media::VideoCapture* capture, |
| 197 scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { | 185 scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { |
| 198 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); | 186 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); |
| 199 | 187 |
| 200 if (available_frames_.size() == 0 || kNormal != state_) { | 188 if (frame_ready_cb_.is_null() || kNormal != state_) { |
| 201 capture->FeedBuffer(buf); | 189 capture->FeedBuffer(buf); |
| 202 return; | 190 return; |
| 203 } | 191 } |
| 204 | 192 |
| 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) { | 193 if (buf->width != capability_.width || buf->height != capability_.height) { |
| 209 capability_.width = buf->width; | 194 capability_.width = buf->width; |
| 210 capability_.height = buf->height; | 195 capability_.height = buf->height; |
| 211 host()->SetNaturalVideoSize( | 196 host()->SetNaturalVideoSize( |
| 212 gfx::Size(capability_.width, capability_.height)); | 197 gfx::Size(capability_.width, capability_.height)); |
| 213 } | 198 } |
| 214 | 199 |
| 215 // Check if there's a size change. | 200 // Always allocate a new frame. |
| 216 if (static_cast<int>(video_frame->width()) != capability_.width || | 201 // |
| 217 static_cast<int>(video_frame->height()) != capability_.height) { | 202 // TODO(scherkus): migrate this to proper buffer recycling. |
| 218 // Allocate new buffer based on the new size. | 203 scoped_refptr<media::VideoFrame> video_frame = |
| 219 video_frame = media::VideoFrame::CreateFrame(media::VideoFrame::YV12, | 204 media::VideoFrame::CreateFrame(media::VideoFrame::YV12, |
| 220 capability_.width, | 205 capability_.width, |
| 221 capability_.height, | 206 capability_.height, |
| 222 media::kNoTimestamp, | 207 buf->timestamp - start_time_, |
| 223 media::kNoTimestamp); | 208 base::TimeDelta::FromMilliseconds(33)); |
| 224 } | |
| 225 | |
| 226 video_frame->SetTimestamp(buf->timestamp - start_time_); | |
| 227 video_frame->SetDuration(base::TimeDelta::FromMilliseconds(33)); | |
| 228 | 209 |
| 229 uint8* buffer = buf->memory_pointer; | 210 uint8* buffer = buf->memory_pointer; |
| 230 | 211 |
| 231 // Assume YV12 format. | 212 // Assume YV12 format. |
| 232 // TODO(vrk): This DCHECK fails in content_unittests ... it should not! | 213 // TODO(vrk): This DCHECK fails in content_unittests ... it should not! |
| 233 // DCHECK(capability_.raw_type == media::VideoFrame::YV12); | 214 // DCHECK(capability_.raw_type == media::VideoFrame::YV12); |
| 234 int y_width = capability_.width; | 215 int y_width = capability_.width; |
| 235 int y_height = capability_.height; | 216 int y_height = capability_.height; |
| 236 int uv_width = capability_.width / 2; | 217 int uv_width = capability_.width / 2; |
| 237 int uv_height = capability_.height / 2; // YV12 format. | 218 int uv_height = capability_.height / 2; // YV12 format. |
| 238 CopyYPlane(buffer, y_width, y_height, video_frame); | 219 CopyYPlane(buffer, y_width, y_height, video_frame); |
| 239 buffer += y_width * y_height; | 220 buffer += y_width * y_height; |
| 240 CopyUPlane(buffer, uv_width, uv_height, video_frame); | 221 CopyUPlane(buffer, uv_width, uv_height, video_frame); |
| 241 buffer += uv_width * uv_height; | 222 buffer += uv_width * uv_height; |
| 242 CopyVPlane(buffer, uv_width, uv_height, video_frame); | 223 CopyVPlane(buffer, uv_width, uv_height, video_frame); |
| 243 | 224 |
| 244 VideoFrameReady(video_frame); | 225 DeliverFrame(video_frame); |
| 245 capture->FeedBuffer(buf); | 226 capture->FeedBuffer(buf); |
| 246 } | 227 } |
| 228 |
| 229 void CaptureVideoDecoder::DeliverFrame( |
| 230 const scoped_refptr<media::VideoFrame>& video_frame) { |
| 231 // Reset the callback before running to protect against reentrancy. |
| 232 FrameReadyCB frame_ready_cb = frame_ready_cb_; |
| 233 frame_ready_cb_.Reset(); |
| 234 frame_ready_cb.Run(video_frame); |
| 235 } |
| OLD | NEW |