Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Unified Diff: content/renderer/media/video_capture_impl.cc

Issue 6902166: Add VideoCaptureImpl (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/media/video_capture_impl.cc
===================================================================
--- content/renderer/media/video_capture_impl.cc (revision 0)
+++ content/renderer/media/video_capture_impl.cc (revision 0)
@@ -0,0 +1,383 @@
+// 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_impl.h"
+
+#include "content/common/child_process.h"
+#include "content/common/video_capture_messages.h"
+#include "content/common/view_messages.h"
+
+VideoCaptureImpl::DIBBuffer::DIBBuffer(
+ TransportDIB* d, media::VideoCapture::VideoFrameBuffer* ptr)
+ : dib(d),
+ mapped_memory(ptr) {
scherkus (not reviewing) 2011/05/23 03:45:54 indentation
wjia(left Chromium) 2011/05/23 21:23:52 Done.
+ }
+
+VideoCaptureImpl::DIBBuffer::~DIBBuffer() {
+ delete dib;
+}
+
+bool VideoCaptureImpl::CaptureStarted() {
+ return state_ == kStarted;
+}
+
+int VideoCaptureImpl::CaptureWidth() {
+ return width_;
+}
+
+int VideoCaptureImpl::CaptureHeight() {
+ return height_;
+}
+
+int VideoCaptureImpl::CaptureFrameRate() {
+ return frame_rate_;
+}
+
+VideoCaptureImpl::VideoCaptureImpl(
+ const media::VideoCaptureSessionId id,
+ scoped_refptr<base::MessageLoopProxy> ml_proxy,
+ VideoCaptureMessageFilter* filter)
+ : VideoCapture(),
+ message_filter_(filter),
+ session_id_(id),
+ ml_proxy_(ml_proxy),
+ device_id_(0),
+ width_(0),
+ height_(0),
+ frame_rate_(0),
+ video_type_(media::VideoFrame::I420),
+ new_width_(0),
+ new_height_(0),
+ state_(kStopped) {
+ DCHECK(filter);
+}
+
+VideoCaptureImpl::~VideoCaptureImpl() {}
+
+void VideoCaptureImpl::Init() {
+ DCHECK(ChildProcess::current()) << "Must be in the renderer";
+ base::MessageLoopProxy* message_loop_proxy =
+ ChildProcess::current()->io_message_loop_proxy();
+ DCHECK(message_loop_proxy);
+
+ if (!message_loop_proxy->BelongsToCurrentThread()) {
+ message_loop_proxy->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::AddDelegateOnIOThread));
+ return;
+ }
+
+ AddDelegateOnIOThread();
+}
+
+void VideoCaptureImpl::DeInit(Task* task) {
+ DCHECK(ChildProcess::current()) << "Must be in the renderer";
+ base::MessageLoopProxy* message_loop_proxy =
+ ChildProcess::current()->io_message_loop_proxy();
+ DCHECK(message_loop_proxy);
+
+ if (state_ == kStarted)
+ message_filter_->Send(new VideoCaptureHostMsg_Stop(0, device_id_));
+
+ if (!message_loop_proxy->BelongsToCurrentThread()) {
+ message_loop_proxy->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::RemoveDelegateOnIOThread,
+ task));
+ return;
+ }
+
+ RemoveDelegateOnIOThread(task);
+}
+
+void VideoCaptureImpl::StartCapture(
+ media::VideoCapture::EventHandler* handler,
+ const VideoCaptureCapability& capability) {
+ DCHECK_EQ(capability.raw_type, media::VideoFrame::I420);
+
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::StartCapture, handler,
+ capability));
+ return;
+ }
+
+ PendingClient::iterator it = pending_clients_.find(handler);
+ if (!device_id_ || !message_filter_->ReadyToSend()) {
+ if (it != pending_clients_.end() && !it->second) {
+ pending_clients_.erase(it);
+ } else {
+ if (it == pending_clients_.end())
+ pending_clients_[handler] = true;
+
+ ml_proxy_->PostDelayedTask(FROM_HERE,
scherkus (not reviewing) 2011/05/23 03:45:54 so now there is no time out? I don't know which t
wjia(left Chromium) 2011/05/23 21:23:52 The "time out" can be added if desired (e.g., chan
+ NewRunnableMethod(this, &VideoCaptureImpl::StartCapture, handler,
+ capability), 1);
+ }
+ return;
+ }
+
+ if (it != pending_clients_.end())
+ pending_clients_.erase(it);
+
+ if (capability.resolution_fixed && master_clients_.size() &&
+ (capability.width != width_ || capability.height != height_)) {
+ // Can't have 2 master clients with different resolutions.
+ handler->OnError(this, 1);
+ return;
+ }
+
+ clients_[handler] = capability;
+ if (capability.resolution_fixed) {
+ master_clients_.push_back(handler);
+ if (master_clients_.size() > 1)
+ return;
+ }
+
+ if (state_ == kStarted) {
+ // Take the resolution of master client.
+ if (capability.resolution_fixed &&
+ (capability.width != width_ || capability.height != height_)) {
+ new_width_ = capability.width;
+ new_height_ = capability.height;
+ DLOG(INFO) << "StartCapture: Got master client with new resolution "
+ "during started, try to restart.";
+ StopDevice();
+ }
+ handler->OnStarted(this);
+ return;
+ }
+
+ if (state_ == kStopping) {
+ if (capability.resolution_fixed || !pending_start()) {
+ new_width_ = capability.width;
+ new_height_ = capability.height;
+ DLOG(INFO) << "StartCapture: Got new resolution, already in stopping.";
+ }
+ handler->OnStarted(this);
+ return;
+ }
+
+ DCHECK_EQ(clients_.size(), 1ul);
+ video_type_ = capability.raw_type;
+ new_width_ = 0;
+ new_height_ = 0;
+ width_ = capability.width;
+ height_ = capability.height;
+
+ StartCaptureInternal();
+}
+
+void VideoCaptureImpl::StopCapture(media::VideoCapture::EventHandler* handler) {
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::StopCapture, handler));
+ return;
+ }
+
+ PendingClient::iterator it = pending_clients_.find(handler);
+ if (it != pending_clients_.end()) {
+ handler->OnStopped(this);
+ it->second = false;
+ return;
+ }
+
+ if (clients_.find(handler) == clients_.end())
+ return;
+
+ handler->OnStopped(this);
+ clients_.erase(handler);
+ master_clients_.remove(handler);
+
+ // Still have at least one master client.
+ if (master_clients_.size() > 0)
+ return;
+
+ // TODO(wjia): Is it really needed to handle resolution change for non-master
+ // clients, except no client case?
+ if (clients_.size() > 0) {
+ DLOG(INFO) << "StopCapture: No master client.";
+ int maxw = 0;
+ int maxh = 0;
+ for (ClientInfo::iterator it = clients_.begin();
+ it != clients_.end(); it++) {
+ if (it->second.width > maxw && it->second.height > maxh) {
+ maxw = it->second.width;
+ maxh = it->second.height;
+ }
+ }
+
+ if (state_ == kStarted) {
+ // Only handle resolution reduction.
+ if (maxw < width_ && maxh < height_) {
+ new_width_ = maxw;
+ new_height_ = maxh;
+ DLOG(INFO) << "StopCapture: New smaller resolution, stopping ...";
+ StopDevice();
+ }
+ return;
+ }
+
+ if (state_ == kStopping) {
+ new_width_ = maxw;
+ new_height_ = maxh;
+ DLOG(INFO) << "StopCapture: New resolution, during stopping.";
+ return;
+ }
+ } else {
+ new_width_ = width_ = 0;
+ new_height_ = height_ = 0;
+ DLOG(INFO) << "StopCapture: No more client, stopping ...";
+ StopDevice();
+ }
+}
+
+void VideoCaptureImpl::OnBufferReceived(TransportDIB::Handle handle,
+ base::Time timestamp) {
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::OnBufferReceived,
+ handle, timestamp));
+ return;
+ }
+
+ if (state_ != kStarted) {
+ message_filter_->Send(
+ new VideoCaptureHostMsg_BufferReady(0, device_id_, handle));
+ return;
+ }
+
+ media::VideoCapture::VideoFrameBuffer* buffer;
+ CachedDIB::iterator it;
+ for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) {
+ if ((*it)->dib->handle() == handle)
+ break;
+ }
+ if (it == cached_dibs_.end()) {
+ TransportDIB* dib = TransportDIB::Map(handle);
+ buffer = new VideoFrameBuffer();
+ buffer->memory_pointer = dib->memory();
+ buffer->buffer_size = dib->size();
+ buffer->width = width_;
+ buffer->height = height_;
+
+ DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer);
+ cached_dibs_.push_back(dib_buffer);
+ } else {
+ buffer = (*it)->mapped_memory;
+ }
+
+ // TODO(wjia): handle buffer sharing with downstream modules.
+ for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
+ it->first->OnBufferReady(this, buffer);
scherkus (not reviewing) 2011/05/23 03:45:54 over-indented
wjia(left Chromium) 2011/05/23 21:23:52 Done.
+ }
+
+ message_filter_->Send(
+ new VideoCaptureHostMsg_BufferReady(0, device_id_, handle));
+}
+
+void VideoCaptureImpl::OnStateChanged(
+ const media::VideoCapture::State& state) {
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::OnStateChanged, state));
+ return;
+ }
+
+ switch (state) {
+ case media::VideoCapture::kStarted:
+ for (ClientInfo::iterator it = clients_.begin();
+ it != clients_.end(); it++) {
+ it->first->OnStarted(this);
+ }
+ break;
+ case media::VideoCapture::kStopped:
+ state_ = kStopped;
+ DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_;
+ if (pending_start())
+ RestartCapture();
+ break;
+ case media::VideoCapture::kPaused:
+ for (ClientInfo::iterator it = clients_.begin();
+ it != clients_.end(); it++) {
+ it->first->OnPaused(this);
+ }
+ break;
+ case media::VideoCapture::kError:
+ for (ClientInfo::iterator it = clients_.begin();
+ it != clients_.end(); it++) {
+ // TODO(wjia): browser process would send error code.
+ it->first->OnError(this, 1);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void VideoCaptureImpl::OnDeviceInfoReceived(
+ const media::VideoCaptureParams& device_info) {
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::OnDeviceInfoReceived,
+ device_info));
+ return;
+ }
+
+ for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
+ it->first->OnDeviceInfoReceived(this, device_info);
+ }
+}
+
+void VideoCaptureImpl::StopDevice() {
+ if (!ml_proxy_->BelongsToCurrentThread()) {
+ ml_proxy_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &VideoCaptureImpl::StopDevice));
+ return;
+ }
+
+ if (state_ == kStarted) {
+ state_ = kStopping;
+ message_filter_->Send(new VideoCaptureHostMsg_Stop(0, device_id_));
+ width_ = height_ = 0;
+ }
+}
+
+void VideoCaptureImpl::RestartCapture() {
+ DCHECK(ml_proxy_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, kStopped);
+
+ width_ = new_width_;
+ height_ = new_height_;
+ new_width_ = 0;
+ new_height_ = 0;
+
+ DLOG(INFO) << "RestartCapture, " << width_ << ", " << height_;
+ StartCaptureInternal();
+}
+
+void VideoCaptureImpl::StartCaptureInternal() {
+ DCHECK(ml_proxy_->BelongsToCurrentThread());
+ DCHECK(device_id_);
+ DCHECK(message_filter_->ReadyToSend());
+
+ media::VideoCaptureParams params;
+ params.width = width_;
+ params.height = height_;
+ params.session_id = session_id_;
+
+ message_filter_->Send(new VideoCaptureHostMsg_Start(0, device_id_, params));
+ state_ = kStarted;
+ for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) {
+ it->first->OnStarted(this);
+ }
+}
+
+void VideoCaptureImpl::AddDelegateOnIOThread() {
+ // |device_id_| is modified only on io thread.
+ device_id_ = message_filter_->AddDelegate(this);
+}
+
+void VideoCaptureImpl::RemoveDelegateOnIOThread(Task* task) {
+ message_filter_->RemoveDelegate(this);
+ media::AutoTaskRunner auto_runner(task);
+}
Property changes on: content/renderer/media/video_capture_impl.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698