blob: bc7c8c19d7de971ad75f514774e2229af69ec8b7 [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/browser/renderer_host/media/video_capture_host.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
#include "content/common/media/video_capture_messages.h"
namespace content {
struct VideoCaptureHost::Entry {
Entry(VideoCaptureController* controller)
: controller(controller) {}
~Entry() {}
scoped_refptr<VideoCaptureController> controller;
};
VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager)
: media_stream_manager_(media_stream_manager) {
}
VideoCaptureHost::~VideoCaptureHost() {}
void VideoCaptureHost::OnChannelClosing() {
BrowserMessageFilter::OnChannelClosing();
// Since the IPC channel is gone, close all requested VideCaptureDevices.
for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); it++) {
VideoCaptureController* controller = it->second->controller.get();
if (controller) {
VideoCaptureControllerID controller_id(it->first);
controller->StopCapture(controller_id, this);
media_stream_manager_->video_capture_manager()->RemoveController(
controller, this);
}
}
STLDeleteValues(&entries_);
}
void VideoCaptureHost::OnDestruct() const {
BrowserThread::DeleteOnIOThread::Destruct(this);
}
///////////////////////////////////////////////////////////////////////////////
// Implements VideoCaptureControllerEventHandler.
void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) {
DVLOG(1) << "VideoCaptureHost::OnError";
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread,
this, controller_id));
}
void VideoCaptureHost::OnBufferCreated(
const VideoCaptureControllerID& controller_id,
base::SharedMemoryHandle handle,
int length,
int buffer_id) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread,
this, controller_id, handle, length, buffer_id));
}
void VideoCaptureHost::OnBufferReady(
const VideoCaptureControllerID& controller_id,
int buffer_id,
base::Time timestamp) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread,
this, controller_id, buffer_id, timestamp));
}
void VideoCaptureHost::OnFrameInfo(
const VideoCaptureControllerID& controller_id,
const media::VideoCaptureCapability& format) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&VideoCaptureHost::DoSendFrameInfoOnIOThread,
this, controller_id, format));
}
void VideoCaptureHost::OnFrameInfoChanged(
const VideoCaptureControllerID& controller_id,
int width,
int height,
int frame_per_second) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoSendFrameInfoChangedOnIOThread,
this, controller_id, width, height, frame_per_second));
}
void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) {
DVLOG(1) << "VideoCaptureHost::OnEnded";
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id));
}
void VideoCaptureHost::DoSendNewBufferOnIOThread(
const VideoCaptureControllerID& controller_id,
base::SharedMemoryHandle handle,
int length,
int buffer_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (entries_.find(controller_id) == entries_.end())
return;
Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle,
length, buffer_id));
}
void VideoCaptureHost::DoSendFilledBufferOnIOThread(
const VideoCaptureControllerID& controller_id,
int buffer_id, base::Time timestamp) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (entries_.find(controller_id) == entries_.end())
return;
Send(new VideoCaptureMsg_BufferReady(controller_id.device_id, buffer_id,
timestamp));
}
void VideoCaptureHost::DoHandleErrorOnIOThread(
const VideoCaptureControllerID& controller_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (entries_.find(controller_id) == entries_.end())
return;
Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
VIDEO_CAPTURE_STATE_ERROR));
DeleteVideoCaptureControllerOnIOThread(controller_id);
}
void VideoCaptureHost::DoEndedOnIOThread(
const VideoCaptureControllerID& controller_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread";
if (entries_.find(controller_id) == entries_.end())
return;
Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
VIDEO_CAPTURE_STATE_ENDED));
DeleteVideoCaptureControllerOnIOThread(controller_id);
}
void VideoCaptureHost::DoSendFrameInfoOnIOThread(
const VideoCaptureControllerID& controller_id,
const media::VideoCaptureCapability& format) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (entries_.find(controller_id) == entries_.end())
return;
media::VideoCaptureParams params;
params.width = format.width;
params.height = format.height;
params.frame_per_second = format.frame_rate;
params.frame_size_type = format.frame_size_type;
Send(new VideoCaptureMsg_DeviceInfo(controller_id.device_id, params));
Send(new VideoCaptureMsg_StateChanged(controller_id.device_id,
VIDEO_CAPTURE_STATE_STARTED));
}
void VideoCaptureHost::DoSendFrameInfoChangedOnIOThread(
const VideoCaptureControllerID& controller_id,
int width,
int height,
int frame_per_second) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (entries_.find(controller_id) == entries_.end())
return;
media::VideoCaptureParams params;
params.width = width;
params.height = height;
params.frame_per_second = frame_per_second;
Send(new VideoCaptureMsg_DeviceInfoChanged(controller_id.device_id, params));
}
///////////////////////////////////////////////////////////////////////////////
// IPC Messages handler.
bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(VideoCaptureHost, message, *message_was_ok)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture)
IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
return handled;
}
void VideoCaptureHost::OnStartCapture(int device_id,
const media::VideoCaptureParams& params) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "VideoCaptureHost::OnStartCapture, device_id " << device_id
<< ", (" << params.width << ", " << params.height << ", "
<< params.frame_per_second << ", " << params.session_id
<< ", variable resolution device:"
<< ((params.frame_size_type ==
media::VariableResolutionVideoCaptureDevice) ? "yes" : "no")
<< ")";
VideoCaptureControllerID controller_id(device_id);
DCHECK(entries_.find(controller_id) == entries_.end());
entries_[controller_id] = new Entry(NULL);
media_stream_manager_->video_capture_manager()->AddController(
params, this, base::Bind(&VideoCaptureHost::OnControllerAdded, this,
device_id, params));
}
void VideoCaptureHost::OnControllerAdded(
int device_id, const media::VideoCaptureParams& params,
VideoCaptureController* controller) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread,
this, device_id, params, make_scoped_refptr(controller)));
}
void VideoCaptureHost::DoControllerAddedOnIOThread(
int device_id, const media::VideoCaptureParams params,
VideoCaptureController* controller) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
VideoCaptureControllerID controller_id(device_id);
EntryMap::iterator it = entries_.find(controller_id);
if (it == entries_.end()) {
if (controller) {
media_stream_manager_->video_capture_manager()->RemoveController(
controller, this);
}
return;
}
if (controller == NULL) {
Send(new VideoCaptureMsg_StateChanged(device_id,
VIDEO_CAPTURE_STATE_ERROR));
delete it->second;
entries_.erase(controller_id);
return;
}
it->second->controller = controller;
controller->StartCapture(controller_id, this, PeerHandle(), params);
}
void VideoCaptureHost::OnStopCapture(int device_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id;
VideoCaptureControllerID controller_id(device_id);
Send(new VideoCaptureMsg_StateChanged(device_id,
VIDEO_CAPTURE_STATE_STOPPED));
DeleteVideoCaptureControllerOnIOThread(controller_id);
}
void VideoCaptureHost::OnPauseCapture(int device_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id;
// Not used.
Send(new VideoCaptureMsg_StateChanged(device_id, VIDEO_CAPTURE_STATE_ERROR));
}
void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id, int buffer_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
VideoCaptureControllerID controller_id(device_id);
EntryMap::iterator it = entries_.find(controller_id);
if (it != entries_.end()) {
scoped_refptr<VideoCaptureController> controller = it->second->controller;
if (controller.get())
controller->ReturnBuffer(controller_id, this, buffer_id);
}
}
void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread(
const VideoCaptureControllerID& controller_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
EntryMap::iterator it = entries_.find(controller_id);
if (it == entries_.end())
return;
VideoCaptureController* controller = it->second->controller.get();
if (controller) {
controller->StopCapture(controller_id, this);
media_stream_manager_->video_capture_manager()->RemoveController(
controller, this);
}
delete it->second;
entries_.erase(controller_id);
}
} // namespace content