blob: 75090d3b57eb0fa1ce3b515b7043ce6f35b94f7d [file] [log] [blame]
// Copyright (c) 2012 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"),
stopped_event_(false, false),
vc_manager_(vc_manager),
state_(video_capture::kStopped),
width_(-1),
height_(-1),
frame_rate_(-1),
video_type_(webrtc::kVideoI420),
capture_engine_(NULL),
ref_count_(0) {
DCHECK(vc_manager_);
Init();
}
VideoCaptureModuleImpl::~VideoCaptureModuleImpl() {
// Ensure to stop capture in case user doesn't do it.
StopCapture();
vc_manager_->RemoveDevice(session_id_, this);
// Ensure capture stopped by |capture_engine_| since all tasks posted on this
// thread will be executed and VCMImpl is waiting for OnStopped signal from
// |capture_engine_|.
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() {
DVLOG(1) << "VideoCaptureModuleImpl::AddRef()";
return base::subtle::Barrier_AtomicIncrement(&ref_count_, 1);
}
int32_t VideoCaptureModuleImpl::Release() {
DVLOG(1) << "VideoCaptureModuleImpl::Release()";
int ret = base::subtle::Barrier_AtomicIncrement(&ref_count_, -1);
if (ret == 0) {
DVLOG(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,
base::Unretained(this), capability));
return 0;
}
WebRtc_Word32 VideoCaptureModuleImpl::StopCapture() {
message_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureModuleImpl::StopCaptureOnCaptureThread,
base::Unretained(this)));
return 0;
}
bool VideoCaptureModuleImpl::CaptureStarted() {
return state_ == video_capture::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) {
stopped_event_.Signal();
}
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,
base::Unretained(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_, video_capture::kStarted);
DVLOG(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_ = video_capture::kStarted;
media::VideoCaptureCapability cap;
cap.width = capability.width;
cap.height = capability.height;
cap.frame_rate = capability.maxFPS;
cap.color = media::VideoCaptureCapability::kI420;
capture_engine_->StartCapture(this, cap);
}
void VideoCaptureModuleImpl::StopCaptureOnCaptureThread() {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
if (state_ != video_capture::kStarted) {
DVLOG(1) << "Got a StopCapture while not started!!! ";
return;
}
DVLOG(1) << "StopCaptureOnCaptureThread. ";
capture_engine_->StopCapture(this);
// Need to use synchronous mode here to make sure |capture_engine_| will
// not call VCMImpl after this function returns. Otherwise, there could be
// use-after-free, especially when StopCapture() is called from dtor.
stopped_event_.Wait();
DVLOG(1) << "Capture Stopped!!! ";
state_ = video_capture::kStopped;
width_ = -1;
height_ = -1;
frame_rate_ = -1;
}
void VideoCaptureModuleImpl::OnBufferReadyOnCaptureThread(
media::VideoCapture* capture,
scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
DCHECK(message_loop_proxy_->BelongsToCurrentThread());
if (state_ != video_capture::kStarted)
return;
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_).InMilliseconds()));
capture->FeedBuffer(buf);
}