Index: content/renderer/media/video_capture_impl.cc |
=================================================================== |
--- content/renderer/media/video_capture_impl.cc (revision 107874) |
+++ content/renderer/media/video_capture_impl.cc (working copy) |
@@ -9,15 +9,24 @@ |
#include "content/common/child_process.h" |
#include "content/common/media/video_capture_messages.h" |
-VideoCaptureImpl::DIBBuffer::DIBBuffer( |
- base::SharedMemory* d, media::VideoCapture::VideoFrameBuffer* ptr) |
- : dib(d), |
- mapped_memory(ptr) {} |
+struct VideoCaptureImpl::DIBBuffer { |
+ public: |
+ DIBBuffer( |
+ base::SharedMemory* d, |
+ media::VideoCapture::VideoFrameBuffer* ptr) |
+ : dib(d), |
+ mapped_memory(ptr), |
+ references(0) { |
+ } |
+ ~DIBBuffer() {} |
-VideoCaptureImpl::DIBBuffer::~DIBBuffer() { |
- delete dib; |
-} |
+ scoped_ptr<base::SharedMemory> dib; |
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> mapped_memory; |
+ // Number of clients which hold this DIB. |
+ int references; |
+}; |
+ |
bool VideoCaptureImpl::CaptureStarted() { |
return state_ == kStarted; |
} |
@@ -47,8 +56,7 @@ |
state_(kStopped) { |
DCHECK(filter); |
memset(¤t_params_, 0, sizeof(current_params_)); |
- memset(&new_params_, 0, sizeof(new_params_)); |
- current_params_.session_id = new_params_.session_id = id; |
+ current_params_.session_id = id; |
} |
VideoCaptureImpl::~VideoCaptureImpl() { |
@@ -147,81 +155,62 @@ |
const VideoCaptureCapability& capability) { |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
- if (pending_clients_.find(handler) != pending_clients_.end() || |
+ if (state_ == kError) { |
+ handler->OnError(this, 1); |
+ handler->OnRemoved(this); |
+ return; |
+ } |
+ |
+ ClientInfo::iterator it1 = clients_pending_on_filter_.find(handler); |
+ ClientInfo::iterator it2 = clients_pending_on_restart_.find(handler); |
+ if (it1 != clients_pending_on_filter_.end() || |
+ it2 != clients_pending_on_restart_.end() || |
clients_.find(handler) != clients_.end() ) { |
// This client has started. |
return; |
} |
if (!device_id_) { |
- pending_clients_[handler] = capability; |
+ clients_pending_on_filter_[handler] = capability; |
return; |
} |
- if (capability.resolution_fixed && master_clients_.size()) { |
- bool matches_current_params = |
- CapabilityMatchesParameters(capability, current_params_); |
- bool matches_new_params = |
- CapabilityMatchesParameters(capability, new_params_); |
- if ((state_ == kStarted && !matches_current_params) || |
- (state_ == kStopping && !matches_new_params)) { |
- // Can't have 2 master clients with different resolutions. |
- handler->OnError(this, 1); |
- handler->OnRemoved(this); |
- return; |
- } |
- } |
- |
handler->OnStarted(this); |
- clients_[handler] = capability; |
- if (capability.resolution_fixed) { |
- master_clients_.push_back(handler); |
- if (master_clients_.size() > 1) { |
- if (device_info_available_) |
- handler->OnDeviceInfoReceived(this, device_info_); |
+ if (state_ == kStarted) { |
+ if (capability.width > current_params_.width || |
+ capability.height > current_params_.height) { |
+ StopDevice(); |
+ DVLOG(1) << "StartCapture: Got client with higher resolution (" |
+ << capability.width << ", " << capability.height << ") " |
+ << "after started, try to restart."; |
+ clients_pending_on_restart_[handler] = capability; |
return; |
} |
- } |
- if (state_ == kStarted) { |
- // Take the resolution of master client. |
- if (capability.resolution_fixed && |
- !CapabilityMatchesParameters(capability, current_params_)) { |
- new_params_.width = capability.width; |
- new_params_.height = capability.height; |
- new_params_.frame_per_second = capability.max_fps; |
- DLOG(INFO) << "StartCapture: Got master client with new resolution (" |
- << new_params_.width << ", " << new_params_.height << ") " |
- << "during started, try to restart."; |
- StopDevice(); |
- } else if (device_info_available_) { |
+ if (device_info_available_) { |
handler->OnDeviceInfoReceived(this, device_info_); |
} |
+ |
+ clients_[handler] = capability; |
return; |
} |
if (state_ == kStopping) { |
- if (capability.resolution_fixed || !pending_start()) { |
- new_params_.width = capability.width; |
- new_params_.height = capability.height; |
- new_params_.frame_per_second = capability.max_fps; |
- DLOG(INFO) << "StartCapture: Got new resolution (" |
- << new_params_.width << ", " << new_params_.height << ") " |
- << ", already in stopping."; |
- } |
+ clients_pending_on_restart_[handler] = capability; |
+ DVLOG(1) << "StartCapture: Got new resolution (" |
+ << capability.width << ", " << capability.height << ") " |
+ << ", during stopping."; |
return; |
} |
+ clients_[handler] = capability; |
DCHECK_EQ(clients_.size(), 1ul); |
video_type_ = capability.raw_type; |
- new_params_.width = 0; |
- new_params_.height = 0; |
- new_params_.frame_per_second = 0; |
current_params_.width = capability.width; |
current_params_.height = capability.height; |
current_params_.frame_per_second = capability.max_fps; |
- DLOG(INFO) << "StartCapture: resolution (" |
- << current_params_.width << ", " << current_params_.height << ")"; |
+ DVLOG(1) << "StartCapture: starting with first resolution (" |
+ << current_params_.width << ", " << current_params_.height << ")"; |
StartCaptureInternal(); |
} |
@@ -230,13 +219,20 @@ |
media::VideoCapture::EventHandler* handler) { |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
- ClientInfo::iterator it = pending_clients_.find(handler); |
- if (it != pending_clients_.end()) { |
+ ClientInfo::iterator it = clients_pending_on_filter_.find(handler); |
+ if (it != clients_pending_on_filter_.end()) { |
handler->OnStopped(this); |
handler->OnRemoved(this); |
- pending_clients_.erase(it); |
+ clients_pending_on_filter_.erase(it); |
return; |
} |
+ it = clients_pending_on_restart_.find(handler); |
+ if (it != clients_pending_on_restart_.end()) { |
+ handler->OnStopped(this); |
+ handler->OnRemoved(this); |
+ clients_pending_on_filter_.erase(it); |
+ return; |
+ } |
if (clients_.find(handler) == clients_.end()) |
return; |
@@ -244,64 +240,15 @@ |
handler->OnStopped(this); |
handler->OnRemoved(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 max_width = 0; |
- int max_height = 0; |
- int frame_rate = 0; |
- for (ClientInfo::iterator it = clients_.begin(); |
- it != clients_.end(); it++) { |
- if (it->second.width > max_width && it->second.height > max_height) { |
- max_width = it->second.width; |
- max_height = it->second.height; |
- frame_rate = it->second.max_fps; |
- } |
- } |
- |
- if (state_ == kStarted) { |
- // Only handle resolution reduction. |
- if (max_width < current_params_.width && |
- max_height < current_params_.height) { |
- new_params_.width = max_width; |
- new_params_.height = max_height; |
- new_params_.frame_per_second = frame_rate; |
- DLOG(INFO) << "StopCapture: New smaller resolution (" |
- << new_params_.width << ", " << new_params_.height << ") " |
- << "), stopping ..."; |
- StopDevice(); |
- } |
- return; |
- } |
- |
- if (state_ == kStopping) { |
- new_params_.width = max_width; |
- new_params_.height = max_height; |
- new_params_.frame_per_second = frame_rate; |
- DLOG(INFO) << "StopCapture: New resolution (" |
- << new_params_.width << ", " << new_params_.height << ") " |
- << "), during stopping."; |
- return; |
- } |
- } else { |
- new_params_.width = current_params_.width = 0; |
- new_params_.height = current_params_.height = 0; |
- new_params_.frame_per_second = current_params_.frame_per_second = 0; |
- DLOG(INFO) << "StopCapture: No more client, stopping ..."; |
+ if (clients_.empty()) { |
+ DVLOG(1) << "StopCapture: No more client, stopping ..."; |
StopDevice(); |
} |
} |
void VideoCaptureImpl::DoFeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) { |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
- DCHECK(client_side_dibs_.find(buffer) != client_side_dibs_.end()); |
CachedDIB::iterator it; |
for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) { |
@@ -310,11 +257,10 @@ |
} |
DCHECK(it != cached_dibs_.end()); |
- if (client_side_dibs_[buffer] <= 1) { |
- client_side_dibs_.erase(buffer); |
+ DCHECK_GT(it->second->references, 0); |
+ it->second->references--; |
+ if (it->second->references == 0) { |
Send(new VideoCaptureHostMsg_BufferReady(device_id_, it->first)); |
- } else { |
- client_side_dibs_[buffer]--; |
} |
} |
@@ -322,6 +268,7 @@ |
base::SharedMemoryHandle handle, |
int length, int buffer_id) { |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
+ DCHECK(device_info_available_); |
media::VideoCapture::VideoFrameBuffer* buffer; |
DCHECK(cached_dibs_.find(buffer_id) == cached_dibs_.end()); |
@@ -331,8 +278,9 @@ |
buffer = new VideoFrameBuffer(); |
buffer->memory_pointer = static_cast<uint8*>(dib->memory()); |
buffer->buffer_size = length; |
- buffer->width = current_params_.width; |
- buffer->height = current_params_.height; |
+ buffer->width = device_info_.width; |
+ buffer->height = device_info_.height; |
+ buffer->stride = device_info_.width; |
DIBBuffer* dib_buffer = new DIBBuffer(dib, buffer); |
cached_dibs_[buffer_id] = dib_buffer; |
@@ -353,7 +301,7 @@ |
for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) { |
it->first->OnBufferReady(this, buffer); |
} |
- client_side_dibs_[buffer] = clients_.size(); |
+ cached_dibs_[buffer_id]->references = clients_.size(); |
} |
void VideoCaptureImpl::DoStateChanged(const media::VideoCapture::State& state) { |
@@ -364,9 +312,9 @@ |
break; |
case media::VideoCapture::kStopped: |
state_ = kStopped; |
- DLOG(INFO) << "OnStateChanged: stopped!, device_id = " << device_id_; |
+ DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
STLDeleteValues(&cached_dibs_); |
- if (pending_start()) |
+ if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
RestartCapture(); |
break; |
case media::VideoCapture::kPaused: |
@@ -376,6 +324,7 @@ |
} |
break; |
case media::VideoCapture::kError: |
+ DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; |
for (ClientInfo::iterator it = clients_.begin(); |
it != clients_.end(); it++) { |
// TODO(wjia): browser process would send error code. |
@@ -383,9 +332,7 @@ |
it->first->OnRemoved(this); |
} |
clients_.clear(); |
- master_clients_.clear(); |
- state_ = kStopped; |
- current_params_.width = current_params_.height = 0; |
+ state_ = kError; |
break; |
default: |
break; |
@@ -395,9 +342,10 @@ |
void VideoCaptureImpl::DoDeviceInfoReceived( |
const media::VideoCaptureParams& device_info) { |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
- if (state_ != kStarted) |
- return; |
+ DCHECK(!ClientHasDIB()); |
+ STLDeleteValues(&cached_dibs_); |
+ |
device_info_ = device_info; |
device_info_available_ = true; |
for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); it++) { |
@@ -406,15 +354,15 @@ |
} |
void VideoCaptureImpl::DoDelegateAdded(int32 device_id) { |
- DLOG(INFO) << "DoDelegateAdded: device_id " << device_id; |
+ DVLOG(1) << "DoDelegateAdded: device_id " << device_id; |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
device_id_ = device_id; |
- for (ClientInfo::iterator it = pending_clients_.begin(); |
- it != pending_clients_.end(); ) { |
+ for (ClientInfo::iterator it = clients_pending_on_filter_.begin(); |
+ it != clients_pending_on_filter_.end(); ) { |
media::VideoCapture::EventHandler* handler = it->first; |
const VideoCaptureCapability capability = it->second; |
- pending_clients_.erase(it++); |
+ clients_pending_on_filter_.erase(it++); |
StartCapture(handler, capability); |
} |
} |
@@ -434,16 +382,28 @@ |
DCHECK(ml_proxy_->BelongsToCurrentThread()); |
DCHECK_EQ(state_, kStopped); |
- current_params_.width = new_params_.width; |
- current_params_.height = new_params_.height; |
- current_params_.frame_per_second = new_params_.frame_per_second; |
- |
- new_params_.width = 0; |
- new_params_.height = 0; |
- new_params_.frame_per_second = 0; |
- |
- DLOG(INFO) << "RestartCapture, " << current_params_.width << ", " |
- << current_params_.height; |
+ int width = 0; |
+ int height = 0; |
+ for (ClientInfo::iterator it = clients_.begin(); |
+ it != clients_.end(); it++) { |
+ if (it->second.width > width) |
+ width = it->second.width; |
+ if (it->second.height > height) |
+ height = it->second.height; |
+ } |
+ for (ClientInfo::iterator it = clients_pending_on_restart_.begin(); |
+ it != clients_pending_on_restart_.end(); ) { |
+ if (it->second.width > width) |
+ width = it->second.width; |
+ if (it->second.height > height) |
+ height = it->second.height; |
+ clients_[it->first] = it->second; |
+ clients_pending_on_restart_.erase(it++); |
+ } |
+ current_params_.width = width; |
+ current_params_.height = height; |
+ DVLOG(1) << "RestartCapture, " << current_params_.width << ", " |
+ << current_params_.height; |
StartCaptureInternal(); |
} |
@@ -473,10 +433,11 @@ |
message_filter_.get(), message))); |
} |
-bool VideoCaptureImpl::CapabilityMatchesParameters( |
- const VideoCaptureCapability& capability, |
- const media::VideoCaptureParams& params) { |
- return (capability.width == params.width && |
- capability.height == params.height && |
- capability.max_fps == params.frame_per_second); |
+bool VideoCaptureImpl::ClientHasDIB() { |
+ CachedDIB::iterator it; |
+ for (it = cached_dibs_.begin(); it != cached_dibs_.end(); it++) { |
+ if (it->second->references > 0) |
+ return true; |
+ } |
+ return false; |
} |