// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/renderer/media/video_capture_module_impl.h" #include "base/atomicops.h" #include "base/bind.h" #include "content/renderer/media/video_capture_impl_manager.h" VideoCaptureModuleImpl::VideoCaptureModuleImpl( const media::VideoCaptureSessionId id, VideoCaptureImplManager* vc_manager) : webrtc::videocapturemodule::VideoCaptureImpl(id), session_id_(id), thread_("VideoCaptureModuleImpl"), vc_manager_(vc_manager), state_(media::VideoCapture::kStopped), got_first_frame_(false), width_(-1), height_(-1), frame_rate_(-1), video_type_(webrtc::kVideoI420), capture_engine_(NULL), pending_start_(false), ref_count_(0) { DCHECK(vc_manager_); Init(); } VideoCaptureModuleImpl::~VideoCaptureModuleImpl() { vc_manager_->RemoveDevice(session_id_, this); thread_.Stop(); } void VideoCaptureModuleImpl::Init() { thread_.Start(); message_loop_proxy_ = thread_.message_loop_proxy(); capture_engine_ = vc_manager_->AddDevice(session_id_, this); } int32_t VideoCaptureModuleImpl::AddRef() { VLOG(1) << "VideoCaptureModuleImpl::AddRef()"; return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1); } int32_t VideoCaptureModuleImpl::Release() { VLOG(1) << "VideoCaptureModuleImpl::Release()"; int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1); if (ret == 0) { VLOG(1) << "Reference count is zero, hence this object is now deleted."; delete this; } return ret; } WebRtc_Word32 VideoCaptureModuleImpl::StartCapture( const webrtc::VideoCaptureCapability& capability) { message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&VideoCaptureModuleImpl::StartCaptureOnCaptureThread, this, capability)); return 0; } WebRtc_Word32 VideoCaptureModuleImpl::StopCapture() { message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&VideoCaptureModuleImpl::StopCaptureOnCaptureThread, this)); return 0; } bool VideoCaptureModuleImpl::CaptureStarted() { return state_ == media::VideoCapture::kStarted; } WebRtc_Word32 VideoCaptureModuleImpl::CaptureSettings( webrtc::VideoCaptureCapability& settings) { settings.width = width_; settings.height = height_; settings.maxFPS = frame_rate_; settings.expectedCaptureDelay = 120; settings.rawType = webrtc::kVideoI420; return 0; } void VideoCaptureModuleImpl::OnStarted(media::VideoCapture* capture) { NOTIMPLEMENTED(); } void VideoCaptureModuleImpl::OnStopped(media::VideoCapture* capture) { message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&VideoCaptureModuleImpl::OnStoppedOnCaptureThread, this, capture)); } void VideoCaptureModuleImpl::OnPaused(media::VideoCapture* capture) { NOTIMPLEMENTED(); } void VideoCaptureModuleImpl::OnError(media::VideoCapture* capture, int error_code) { NOTIMPLEMENTED(); } void VideoCaptureModuleImpl::OnRemoved(media::VideoCapture* capture) { NOTIMPLEMENTED(); } void VideoCaptureModuleImpl::OnBufferReady( media::VideoCapture* capture, scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&VideoCaptureModuleImpl::OnBufferReadyOnCaptureThread, this, capture, buf)); } void VideoCaptureModuleImpl::OnDeviceInfoReceived( media::VideoCapture* capture, const media::VideoCaptureParams& device_info) { NOTIMPLEMENTED(); } void VideoCaptureModuleImpl::StartCaptureOnCaptureThread( const webrtc::VideoCaptureCapability& capability) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); DCHECK_NE(state_, media::VideoCapture::kStarted); if (state_ == media::VideoCapture::kStopping) { VLOG(1) << "Got a new StartCapture in Stopping state!!! "; pending_start_ = true; pending_cap_ = capability; return; } VLOG(1) << "StartCaptureOnCaptureThread: " << capability.width << ", " << capability.height; StartCaptureInternal(capability); return; } void VideoCaptureModuleImpl::StartCaptureInternal( const webrtc::VideoCaptureCapability& capability) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); DCHECK_EQ(capability.rawType, webrtc::kVideoI420); video_type_ = capability.rawType; width_ = capability.width; height_ = capability.height; frame_rate_ = capability.maxFPS; state_ = media::VideoCapture::kStarted; media::VideoCapture::VideoCaptureCapability cap; cap.width = capability.width; cap.height = capability.height; cap.max_fps = capability.maxFPS; cap.raw_type = media::VideoFrame::I420; cap.resolution_fixed = true; capture_engine_->StartCapture(this, cap); } void VideoCaptureModuleImpl::StopCaptureOnCaptureThread() { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); if (pending_start_) { VLOG(1) << "Got a StopCapture with one pending start!!! "; pending_start_ = false; return; } if (state_ != media::VideoCapture::kStarted) { VLOG(1) << "Got a StopCapture while not started!!! "; return; } VLOG(1) << "StopCaptureOnCaptureThread. "; state_ = media::VideoCapture::kStopping; capture_engine_->StopCapture(this); return; } void VideoCaptureModuleImpl::OnStoppedOnCaptureThread( media::VideoCapture* capture) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); VLOG(1) << "Capture Stopped!!! "; state_ = media::VideoCapture::kStopped; got_first_frame_ = false; width_ = -1; height_ = -1; frame_rate_ = -1; if (pending_start_) { VLOG(1) << "restart pending start "; pending_start_ = false; StartCaptureInternal(pending_cap_); } } void VideoCaptureModuleImpl::OnBufferReadyOnCaptureThread( media::VideoCapture* capture, scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) { DCHECK(message_loop_proxy_->BelongsToCurrentThread()); if (state_ != media::VideoCapture::kStarted) return; if (!got_first_frame_) { got_first_frame_ = true; start_time_ = buf->timestamp; } frameInfo_.width = buf->width; frameInfo_.height = buf->height; frameInfo_.rawType = video_type_; IncomingFrame( static_cast<WebRtc_UWord8*>(buf->memory_pointer), static_cast<WebRtc_Word32>(buf->buffer_size), frameInfo_, static_cast<WebRtc_Word64>( (buf->timestamp - start_time_).InMicroseconds())); capture->FeedBuffer(buf); }