| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // |
| 5 // Notes about usage of this object by VideoCaptureImplManager. |
| 6 // |
| 7 // VideoCaptureImplManager access this object by using a Unretained() |
| 8 // binding and tasks on the IO thread. It is then important that |
| 9 // VideoCaptureImpl never post task to itself. All operations must be |
| 10 // synchronous. |
| 4 | 11 |
| 5 #include "content/renderer/media/video_capture_impl.h" | 12 #include "content/renderer/media/video_capture_impl.h" |
| 6 | 13 |
| 7 #include "base/bind.h" | 14 #include "base/bind.h" |
| 8 #include "base/stl_util.h" | 15 #include "base/stl_util.h" |
| 9 #include "content/child/child_process.h" | 16 #include "content/child/child_process.h" |
| 10 #include "content/common/media/video_capture_messages.h" | 17 #include "content/common/media/video_capture_messages.h" |
| 11 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
| 12 #include "media/base/limits.h" | 19 #include "media/base/limits.h" |
| 13 #include "media/base/video_frame.h" | 20 #include "media/base/video_frame.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 25 const size_t buffer_size; | 32 const size_t buffer_size; |
| 26 | 33 |
| 27 private: | 34 private: |
| 28 friend class base::RefCountedThreadSafe<ClientBuffer>; | 35 friend class base::RefCountedThreadSafe<ClientBuffer>; |
| 29 | 36 |
| 30 virtual ~ClientBuffer() {} | 37 virtual ~ClientBuffer() {} |
| 31 | 38 |
| 32 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); | 39 DISALLOW_COPY_AND_ASSIGN(ClientBuffer); |
| 33 }; | 40 }; |
| 34 | 41 |
| 35 bool VideoCaptureImpl::CaptureStarted() { | 42 VideoCaptureImpl::ClientInfo::ClientInfo() {} |
| 36 return state_ == VIDEO_CAPTURE_STATE_STARTED; | 43 VideoCaptureImpl::ClientInfo::~ClientInfo() {} |
| 37 } | |
| 38 | |
| 39 int VideoCaptureImpl::CaptureFrameRate() { | |
| 40 return last_frame_format_.frame_rate; | |
| 41 } | |
| 42 | 44 |
| 43 VideoCaptureImpl::VideoCaptureImpl( | 45 VideoCaptureImpl::VideoCaptureImpl( |
| 44 const media::VideoCaptureSessionId session_id, | 46 const media::VideoCaptureSessionId session_id, |
| 45 VideoCaptureMessageFilter* filter) | 47 VideoCaptureMessageFilter* filter) |
| 46 : VideoCapture(), | 48 : message_filter_(filter), |
| 47 message_filter_(filter), | |
| 48 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()), | |
| 49 device_id_(0), | 49 device_id_(0), |
| 50 session_id_(session_id), | 50 session_id_(session_id), |
| 51 suspended_(false), | 51 suspended_(false), |
| 52 state_(VIDEO_CAPTURE_STATE_STOPPED), | 52 state_(VIDEO_CAPTURE_STATE_STOPPED), |
| 53 weak_factory_(this) { | 53 weak_factory_(this) { |
| 54 DCHECK(filter); | 54 DCHECK(filter); |
| 55 thread_checker_.DetachFromThread(); |
| 55 } | 56 } |
| 56 | 57 |
| 57 VideoCaptureImpl::~VideoCaptureImpl() {} | 58 VideoCaptureImpl::~VideoCaptureImpl() { |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); |
| 60 } |
| 58 | 61 |
| 59 void VideoCaptureImpl::Init() { | 62 void VideoCaptureImpl::Init() { |
| 60 io_message_loop_proxy_->PostTask(FROM_HERE, | 63 DCHECK(thread_checker_.CalledOnValidThread()); |
| 61 base::Bind(&VideoCaptureImpl::InitOnIOThread, | 64 message_filter_->AddDelegate(this); |
| 62 base::Unretained(this))); | |
| 63 } | 65 } |
| 64 | 66 |
| 65 void VideoCaptureImpl::DeInit(base::Closure done_cb) { | 67 void VideoCaptureImpl::DeInit() { |
| 66 io_message_loop_proxy_->PostTask(FROM_HERE, | 68 DCHECK(thread_checker_.CalledOnValidThread()); |
| 67 base::Bind(&VideoCaptureImpl::DeInitOnIOThread, | 69 if (state_ == VIDEO_CAPTURE_STATE_STARTED) |
| 68 base::Unretained(this), | 70 Send(new VideoCaptureHostMsg_Stop(device_id_)); |
| 69 done_cb)); | 71 message_filter_->RemoveDelegate(this); |
| 70 } | 72 } |
| 71 | 73 |
| 72 void VideoCaptureImpl::SuspendCapture(bool suspend) { | 74 void VideoCaptureImpl::SuspendCapture(bool suspend) { |
| 73 io_message_loop_proxy_->PostTask(FROM_HERE, | 75 DCHECK(thread_checker_.CalledOnValidThread()); |
| 74 base::Bind(&VideoCaptureImpl::SuspendCaptureOnIOThread, | 76 suspended_ = suspend; |
| 75 base::Unretained(this), | |
| 76 suspend)); | |
| 77 } | 77 } |
| 78 | 78 |
| 79 void VideoCaptureImpl::StartCapture( | 79 void VideoCaptureImpl::StartCapture( |
| 80 media::VideoCapture::EventHandler* handler, | 80 int client_id, |
| 81 const media::VideoCaptureParams& params) { | 81 const media::VideoCaptureParams& params, |
| 82 io_message_loop_proxy_->PostTask(FROM_HERE, | 82 const VideoCaptureStateUpdateCB& state_update_cb, |
| 83 base::Bind(&VideoCaptureImpl::StartCaptureOnIOThread, | 83 const VideoCaptureDeliverFrameCB& deliver_frame_cb) { |
| 84 base::Unretained(this), handler, params)); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 85 } | 85 ClientInfo client_info; |
| 86 client_info.params = params; |
| 87 client_info.state_update_cb = state_update_cb; |
| 88 client_info.deliver_frame_cb = deliver_frame_cb; |
| 86 | 89 |
| 87 void VideoCaptureImpl::StopCapture( | |
| 88 media::VideoCapture::EventHandler* handler) { | |
| 89 io_message_loop_proxy_->PostTask(FROM_HERE, | |
| 90 base::Bind(&VideoCaptureImpl::StopCaptureOnIOThread, | |
| 91 base::Unretained(this), handler)); | |
| 92 } | |
| 93 | |
| 94 void VideoCaptureImpl::GetDeviceSupportedFormats( | |
| 95 const DeviceFormatsCallback& callback) { | |
| 96 DCHECK(!callback.is_null()); | |
| 97 io_message_loop_proxy_->PostTask(FROM_HERE, | |
| 98 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormatsOnIOThread, | |
| 99 base::Unretained(this), media::BindToCurrentLoop(callback))); | |
| 100 } | |
| 101 | |
| 102 void VideoCaptureImpl::GetDeviceFormatsInUse( | |
| 103 const DeviceFormatsInUseCallback& callback) { | |
| 104 DCHECK(!callback.is_null()); | |
| 105 io_message_loop_proxy_->PostTask(FROM_HERE, | |
| 106 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUseOnIOThread, | |
| 107 base::Unretained(this), media::BindToCurrentLoop(callback))); | |
| 108 } | |
| 109 | |
| 110 void VideoCaptureImpl::InitOnIOThread() { | |
| 111 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 112 message_filter_->AddDelegate(this); | |
| 113 } | |
| 114 | |
| 115 void VideoCaptureImpl::DeInitOnIOThread(base::Closure done_cb) { | |
| 116 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 117 if (state_ == VIDEO_CAPTURE_STATE_STARTED) | |
| 118 Send(new VideoCaptureHostMsg_Stop(device_id_)); | |
| 119 message_filter_->RemoveDelegate(this); | |
| 120 done_cb.Run(); | |
| 121 } | |
| 122 | |
| 123 void VideoCaptureImpl::SuspendCaptureOnIOThread(bool suspend) { | |
| 124 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 125 suspended_ = suspend; | |
| 126 } | |
| 127 | |
| 128 void VideoCaptureImpl::StartCaptureOnIOThread( | |
| 129 media::VideoCapture::EventHandler* handler, | |
| 130 const media::VideoCaptureParams& params) { | |
| 131 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 132 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { | 90 if (state_ == VIDEO_CAPTURE_STATE_ERROR) { |
| 133 handler->OnError(this, 1); | 91 state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); |
| 134 handler->OnRemoved(this); | 92 } else if (clients_pending_on_filter_.count(client_id) || |
| 135 } else if ((clients_pending_on_filter_.find(handler) != | 93 clients_pending_on_restart_.count(client_id) || |
| 136 clients_pending_on_filter_.end()) || | 94 clients_.count(client_id)) { |
| 137 (clients_pending_on_restart_.find(handler) != | 95 LOG(FATAL) << "This client has already started."; |
| 138 clients_pending_on_restart_.end()) || | |
| 139 clients_.find(handler) != clients_.end() ) { | |
| 140 // This client has started. | |
| 141 } else if (!device_id_) { | 96 } else if (!device_id_) { |
| 142 clients_pending_on_filter_[handler] = params; | 97 clients_pending_on_filter_[client_id] = client_info; |
| 143 } else { | 98 } else { |
| 144 handler->OnStarted(this); | 99 // Note: |state_| might not be started at this point. But we tell |
| 100 // client that we have started. |
| 101 state_update_cb.Run(VIDEO_CAPTURE_STATE_STARTED); |
| 145 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 102 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 146 clients_[handler] = params; | 103 clients_[client_id] = client_info; |
| 147 // TODO(sheu): Allowing resolution change will require that all | 104 // TODO(sheu): Allowing resolution change will require that all |
| 148 // outstanding clients of a capture session support resolution change. | 105 // outstanding clients of a capture session support resolution change. |
| 149 DCHECK_EQ(params_.allow_resolution_change, | 106 DCHECK_EQ(params_.allow_resolution_change, |
| 150 params.allow_resolution_change); | 107 params.allow_resolution_change); |
| 151 } else if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { | 108 } else if (state_ == VIDEO_CAPTURE_STATE_STOPPING) { |
| 152 clients_pending_on_restart_[handler] = params; | 109 clients_pending_on_restart_[client_id] = client_info; |
| 153 DVLOG(1) << "StartCapture: Got new resolution " | 110 DVLOG(1) << "StartCapture: Got new resolution " |
| 154 << params.requested_format.frame_size.ToString() | 111 << params.requested_format.frame_size.ToString() |
| 155 << " during stopping."; | 112 << " during stopping."; |
| 156 } else { | 113 } else { |
| 157 clients_[handler] = params; | 114 clients_[client_id] = client_info; |
| 158 DCHECK_EQ(1ul, clients_.size()); | 115 if (state_ == VIDEO_CAPTURE_STATE_STARTED) |
| 116 return; |
| 159 params_ = params; | 117 params_ = params; |
| 160 if (params_.requested_format.frame_rate > | 118 if (params_.requested_format.frame_rate > |
| 161 media::limits::kMaxFramesPerSecond) { | 119 media::limits::kMaxFramesPerSecond) { |
| 162 params_.requested_format.frame_rate = | 120 params_.requested_format.frame_rate = |
| 163 media::limits::kMaxFramesPerSecond; | 121 media::limits::kMaxFramesPerSecond; |
| 164 } | 122 } |
| 165 DVLOG(1) << "StartCapture: starting with first resolution " | 123 DVLOG(1) << "StartCapture: starting with first resolution " |
| 166 << params_.requested_format.frame_size.ToString(); | 124 << params_.requested_format.frame_size.ToString(); |
| 167 first_frame_timestamp_ = base::TimeTicks(); | 125 first_frame_timestamp_ = base::TimeTicks(); |
| 168 StartCaptureInternal(); | 126 StartCaptureInternal(); |
| 169 } | 127 } |
| 170 } | 128 } |
| 171 } | 129 } |
| 172 | 130 |
| 173 void VideoCaptureImpl::StopCaptureOnIOThread( | 131 void VideoCaptureImpl::StopCapture(int client_id) { |
| 174 media::VideoCapture::EventHandler* handler) { | 132 DCHECK(thread_checker_.CalledOnValidThread()); |
| 175 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 176 | 133 |
| 177 // A handler can be in only one client list. | 134 // A client ID can be in only one client list. |
| 178 // If this handler is in any client list, we can just remove it from | 135 // If this ID is in any client list, we can just remove it from |
| 179 // that client list and don't have to run the other following RemoveClient(). | 136 // that client list and don't have to run the other following RemoveClient(). |
| 180 RemoveClient(handler, &clients_pending_on_filter_) || | 137 if (!RemoveClient(client_id, &clients_pending_on_filter_)) { |
| 181 RemoveClient(handler, &clients_pending_on_restart_) || | 138 if (!RemoveClient(client_id, &clients_pending_on_restart_)) { |
| 182 RemoveClient(handler, &clients_); | 139 bool removed = RemoveClient(client_id, &clients_); |
| 140 DCHECK(removed) << "Removing a non-existent client."; |
| 141 } |
| 142 } |
| 183 | 143 |
| 184 if (clients_.empty()) { | 144 if (clients_.empty()) { |
| 185 DVLOG(1) << "StopCapture: No more client, stopping ..."; | 145 DVLOG(1) << "StopCapture: No more client, stopping ..."; |
| 186 StopDevice(); | 146 StopDevice(); |
| 187 client_buffers_.clear(); | 147 client_buffers_.clear(); |
| 188 weak_factory_.InvalidateWeakPtrs(); | 148 weak_factory_.InvalidateWeakPtrs(); |
| 189 } | 149 } |
| 190 } | 150 } |
| 191 | 151 |
| 192 void VideoCaptureImpl::GetDeviceSupportedFormatsOnIOThread( | 152 void VideoCaptureImpl::GetDeviceSupportedFormats( |
| 193 const DeviceFormatsCallback& callback) { | 153 const VideoCaptureDeviceFormatsCB& callback) { |
| 194 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 154 DCHECK(thread_checker_.CalledOnValidThread()); |
| 195 device_formats_callback_queue_.push_back(callback); | 155 device_formats_cb_queue_.push_back(callback); |
| 196 if (device_formats_callback_queue_.size() == 1) | 156 if (device_formats_cb_queue_.size() == 1) |
| 197 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_, | 157 Send(new VideoCaptureHostMsg_GetDeviceSupportedFormats(device_id_, |
| 198 session_id_)); | 158 session_id_)); |
| 199 } | 159 } |
| 200 | 160 |
| 201 void VideoCaptureImpl::GetDeviceFormatsInUseOnIOThread( | 161 void VideoCaptureImpl::GetDeviceFormatsInUse( |
| 202 const DeviceFormatsInUseCallback& callback) { | 162 const VideoCaptureDeviceFormatsCB& callback) { |
| 203 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 163 DCHECK(thread_checker_.CalledOnValidThread()); |
| 204 device_formats_in_use_callback_queue_.push_back(callback); | 164 device_formats_in_use_cb_queue_.push_back(callback); |
| 205 if (device_formats_in_use_callback_queue_.size() == 1) | 165 if (device_formats_in_use_cb_queue_.size() == 1) |
| 206 Send( | 166 Send( |
| 207 new VideoCaptureHostMsg_GetDeviceFormatsInUse(device_id_, session_id_)); | 167 new VideoCaptureHostMsg_GetDeviceFormatsInUse(device_id_, session_id_)); |
| 208 } | 168 } |
| 209 | 169 |
| 210 void VideoCaptureImpl::OnBufferCreated( | 170 void VideoCaptureImpl::OnBufferCreated( |
| 211 base::SharedMemoryHandle handle, | 171 base::SharedMemoryHandle handle, |
| 212 int length, int buffer_id) { | 172 int length, int buffer_id) { |
| 213 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 173 DCHECK(thread_checker_.CalledOnValidThread()); |
| 214 | 174 |
| 215 // In case client calls StopCapture before the arrival of created buffer, | 175 // In case client calls StopCapture before the arrival of created buffer, |
| 216 // just close this buffer and return. | 176 // just close this buffer and return. |
| 217 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { | 177 if (state_ != VIDEO_CAPTURE_STATE_STARTED) { |
| 218 base::SharedMemory::CloseHandle(handle); | 178 base::SharedMemory::CloseHandle(handle); |
| 219 return; | 179 return; |
| 220 } | 180 } |
| 221 | 181 |
| 222 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); | 182 scoped_ptr<base::SharedMemory> shm(new base::SharedMemory(handle, false)); |
| 223 if (!shm->Map(length)) { | 183 if (!shm->Map(length)) { |
| 224 DLOG(ERROR) << "OnBufferCreated: Map failed."; | 184 DLOG(ERROR) << "OnBufferCreated: Map failed."; |
| 225 return; | 185 return; |
| 226 } | 186 } |
| 227 | 187 |
| 228 bool inserted = | 188 bool inserted = |
| 229 client_buffers_.insert(std::make_pair( | 189 client_buffers_.insert(std::make_pair( |
| 230 buffer_id, | 190 buffer_id, |
| 231 new ClientBuffer(shm.Pass(), | 191 new ClientBuffer(shm.Pass(), |
| 232 length))).second; | 192 length))).second; |
| 233 DCHECK(inserted); | 193 DCHECK(inserted); |
| 234 } | 194 } |
| 235 | 195 |
| 236 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { | 196 void VideoCaptureImpl::OnBufferDestroyed(int buffer_id) { |
| 237 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 197 DCHECK(thread_checker_.CalledOnValidThread()); |
| 238 | 198 |
| 239 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); | 199 ClientBufferMap::iterator iter = client_buffers_.find(buffer_id); |
| 240 if (iter == client_buffers_.end()) | 200 if (iter == client_buffers_.end()) |
| 241 return; | 201 return; |
| 242 | 202 |
| 243 DCHECK(!iter->second || iter->second->HasOneRef()) | 203 DCHECK(!iter->second || iter->second->HasOneRef()) |
| 244 << "Instructed to delete buffer we are still using."; | 204 << "Instructed to delete buffer we are still using."; |
| 245 client_buffers_.erase(iter); | 205 client_buffers_.erase(iter); |
| 246 } | 206 } |
| 247 | 207 |
| 248 void VideoCaptureImpl::OnBufferReceived(int buffer_id, | 208 void VideoCaptureImpl::OnBufferReceived(int buffer_id, |
| 249 const media::VideoCaptureFormat& format, | 209 const media::VideoCaptureFormat& format, |
| 250 base::TimeTicks timestamp) { | 210 base::TimeTicks timestamp) { |
| 251 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 211 DCHECK(thread_checker_.CalledOnValidThread()); |
| 252 | 212 |
| 253 // The capture pipeline supports only I420 for now. | 213 // The capture pipeline supports only I420 for now. |
| 254 DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420); | 214 DCHECK_EQ(format.pixel_format, media::PIXEL_FORMAT_I420); |
| 255 | 215 |
| 256 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 216 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
| 257 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); | 217 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, 0)); |
| 258 return; | 218 return; |
| 259 } | 219 } |
| 260 | 220 |
| 261 last_frame_format_ = format; | 221 last_frame_format_ = format; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 282 buffer->buffer_size, | 242 buffer->buffer_size, |
| 283 buffer->buffer->handle(), | 243 buffer->buffer->handle(), |
| 284 timestamp - first_frame_timestamp_, | 244 timestamp - first_frame_timestamp_, |
| 285 media::BindToCurrentLoop(base::Bind( | 245 media::BindToCurrentLoop(base::Bind( |
| 286 &VideoCaptureImpl::OnClientBufferFinished, | 246 &VideoCaptureImpl::OnClientBufferFinished, |
| 287 weak_factory_.GetWeakPtr(), | 247 weak_factory_.GetWeakPtr(), |
| 288 buffer_id, | 248 buffer_id, |
| 289 buffer, | 249 buffer, |
| 290 base::Passed(scoped_ptr<gpu::MailboxHolder>().Pass())))); | 250 base::Passed(scoped_ptr<gpu::MailboxHolder>().Pass())))); |
| 291 | 251 |
| 292 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) | 252 for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); |
| 293 it->first->OnFrameReady(this, frame); | 253 ++it) { |
| 254 it->second.deliver_frame_cb.Run(frame, format); |
| 255 } |
| 294 } | 256 } |
| 295 | 257 |
| 296 static void NullReadPixelsCB(const SkBitmap& bitmap) { NOTIMPLEMENTED(); } | 258 static void NullReadPixelsCB(const SkBitmap& bitmap) { NOTIMPLEMENTED(); } |
| 297 | 259 |
| 298 void VideoCaptureImpl::OnMailboxBufferReceived( | 260 void VideoCaptureImpl::OnMailboxBufferReceived( |
| 299 int buffer_id, | 261 int buffer_id, |
| 300 const gpu::MailboxHolder& mailbox_holder, | 262 const gpu::MailboxHolder& mailbox_holder, |
| 301 const media::VideoCaptureFormat& format, | 263 const media::VideoCaptureFormat& format, |
| 302 base::TimeTicks timestamp) { | 264 base::TimeTicks timestamp) { |
| 303 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 265 DCHECK(thread_checker_.CalledOnValidThread()); |
| 304 | 266 |
| 305 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { | 267 if (state_ != VIDEO_CAPTURE_STATE_STARTED || suspended_) { |
| 306 Send(new VideoCaptureHostMsg_BufferReady( | 268 Send(new VideoCaptureHostMsg_BufferReady( |
| 307 device_id_, buffer_id, mailbox_holder.sync_point)); | 269 device_id_, buffer_id, mailbox_holder.sync_point)); |
| 308 return; | 270 return; |
| 309 } | 271 } |
| 310 | 272 |
| 311 last_frame_format_ = format; | 273 last_frame_format_ = format; |
| 312 if (first_frame_timestamp_.is_null()) | 274 if (first_frame_timestamp_.is_null()) |
| 313 first_frame_timestamp_ = timestamp; | 275 first_frame_timestamp_ = timestamp; |
| 314 | 276 |
| 315 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( | 277 scoped_refptr<media::VideoFrame> frame = media::VideoFrame::WrapNativeTexture( |
| 316 make_scoped_ptr(new gpu::MailboxHolder(mailbox_holder)), | 278 make_scoped_ptr(new gpu::MailboxHolder(mailbox_holder)), |
| 317 media::BindToCurrentLoop( | 279 media::BindToCurrentLoop( |
| 318 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, | 280 base::Bind(&VideoCaptureImpl::OnClientBufferFinished, |
| 319 weak_factory_.GetWeakPtr(), | 281 weak_factory_.GetWeakPtr(), |
| 320 buffer_id, | 282 buffer_id, |
| 321 scoped_refptr<ClientBuffer>())), | 283 scoped_refptr<ClientBuffer>())), |
| 322 last_frame_format_.frame_size, | 284 last_frame_format_.frame_size, |
| 323 gfx::Rect(last_frame_format_.frame_size), | 285 gfx::Rect(last_frame_format_.frame_size), |
| 324 last_frame_format_.frame_size, | 286 last_frame_format_.frame_size, |
| 325 timestamp - first_frame_timestamp_, | 287 timestamp - first_frame_timestamp_, |
| 326 base::Bind(&NullReadPixelsCB)); | 288 base::Bind(&NullReadPixelsCB)); |
| 327 | 289 |
| 328 for (ClientInfo::iterator it = clients_.begin(); it != clients_.end(); ++it) | 290 for (ClientInfoMap::iterator it = clients_.begin(); it != clients_.end(); |
| 329 it->first->OnFrameReady(this, frame); | 291 ++it) { |
| 292 it->second.deliver_frame_cb.Run(frame, format); |
| 293 } |
| 330 } | 294 } |
| 331 | 295 |
| 332 void VideoCaptureImpl::OnClientBufferFinished( | 296 void VideoCaptureImpl::OnClientBufferFinished( |
| 333 int buffer_id, | 297 int buffer_id, |
| 334 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, | 298 const scoped_refptr<ClientBuffer>& /* ignored_buffer */, |
| 335 scoped_ptr<gpu::MailboxHolder> mailbox_holder) { | 299 scoped_ptr<gpu::MailboxHolder> mailbox_holder) { |
| 336 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 300 DCHECK(thread_checker_.CalledOnValidThread()); |
| 337 const uint32 sync_point = (mailbox_holder ? mailbox_holder->sync_point : 0); | 301 const uint32 sync_point = (mailbox_holder ? mailbox_holder->sync_point : 0); |
| 338 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, sync_point)); | 302 Send(new VideoCaptureHostMsg_BufferReady(device_id_, buffer_id, sync_point)); |
| 339 } | 303 } |
| 340 | 304 |
| 341 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { | 305 void VideoCaptureImpl::OnStateChanged(VideoCaptureState state) { |
| 342 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 306 DCHECK(thread_checker_.CalledOnValidThread()); |
| 343 | 307 |
| 344 switch (state) { | 308 switch (state) { |
| 345 case VIDEO_CAPTURE_STATE_STARTED: | 309 case VIDEO_CAPTURE_STATE_STARTED: |
| 310 // Camera has started in the browser process. Since we have already |
| 311 // told all clients that we have started there's nothing to do. |
| 346 break; | 312 break; |
| 347 case VIDEO_CAPTURE_STATE_STOPPED: | 313 case VIDEO_CAPTURE_STATE_STOPPED: |
| 348 state_ = VIDEO_CAPTURE_STATE_STOPPED; | 314 state_ = VIDEO_CAPTURE_STATE_STOPPED; |
| 349 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; | 315 DVLOG(1) << "OnStateChanged: stopped!, device_id = " << device_id_; |
| 350 client_buffers_.clear(); | 316 client_buffers_.clear(); |
| 351 weak_factory_.InvalidateWeakPtrs(); | 317 weak_factory_.InvalidateWeakPtrs(); |
| 352 if (!clients_.empty() || !clients_pending_on_restart_.empty()) | 318 if (!clients_.empty() || !clients_pending_on_restart_.empty()) |
| 353 RestartCapture(); | 319 RestartCapture(); |
| 354 break; | 320 break; |
| 355 case VIDEO_CAPTURE_STATE_PAUSED: | 321 case VIDEO_CAPTURE_STATE_PAUSED: |
| 356 for (ClientInfo::iterator it = clients_.begin(); | 322 for (ClientInfoMap::iterator it = clients_.begin(); |
| 357 it != clients_.end(); ++it) { | 323 it != clients_.end(); ++it) { |
| 358 it->first->OnPaused(this); | 324 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED); |
| 359 } | 325 } |
| 360 break; | 326 break; |
| 361 case VIDEO_CAPTURE_STATE_ERROR: | 327 case VIDEO_CAPTURE_STATE_ERROR: |
| 362 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; | 328 DVLOG(1) << "OnStateChanged: error!, device_id = " << device_id_; |
| 363 for (ClientInfo::iterator it = clients_.begin(); | 329 for (ClientInfoMap::iterator it = clients_.begin(); |
| 364 it != clients_.end(); ++it) { | 330 it != clients_.end(); ++it) { |
| 365 // TODO(wjia): browser process would send error code. | 331 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR); |
| 366 it->first->OnError(this, 1); | |
| 367 it->first->OnRemoved(this); | |
| 368 } | 332 } |
| 369 clients_.clear(); | 333 clients_.clear(); |
| 370 state_ = VIDEO_CAPTURE_STATE_ERROR; | 334 state_ = VIDEO_CAPTURE_STATE_ERROR; |
| 371 break; | 335 break; |
| 372 case VIDEO_CAPTURE_STATE_ENDED: | 336 case VIDEO_CAPTURE_STATE_ENDED: |
| 373 DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_; | 337 DVLOG(1) << "OnStateChanged: ended!, device_id = " << device_id_; |
| 374 for (ClientInfo::iterator it = clients_.begin(); | 338 for (ClientInfoMap::iterator it = clients_.begin(); |
| 375 it != clients_.end(); ++it) { | 339 it != clients_.end(); ++it) { |
| 376 it->first->OnRemoved(this); | 340 // We'll only notify the client that the stream has stopped. |
| 341 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); |
| 377 } | 342 } |
| 378 clients_.clear(); | 343 clients_.clear(); |
| 379 state_ = VIDEO_CAPTURE_STATE_ENDED; | 344 state_ = VIDEO_CAPTURE_STATE_ENDED; |
| 380 break; | 345 break; |
| 381 default: | 346 default: |
| 382 break; | 347 break; |
| 383 } | 348 } |
| 384 } | 349 } |
| 385 | 350 |
| 386 void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated( | 351 void VideoCaptureImpl::OnDeviceSupportedFormatsEnumerated( |
| 387 const media::VideoCaptureFormats& supported_formats) { | 352 const media::VideoCaptureFormats& supported_formats) { |
| 388 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 353 DCHECK(thread_checker_.CalledOnValidThread()); |
| 389 for (size_t i = 0; i < device_formats_callback_queue_.size(); ++i) | 354 for (size_t i = 0; i < device_formats_cb_queue_.size(); ++i) |
| 390 device_formats_callback_queue_[i].Run(supported_formats); | 355 device_formats_cb_queue_[i].Run(supported_formats); |
| 391 device_formats_callback_queue_.clear(); | 356 device_formats_cb_queue_.clear(); |
| 392 } | 357 } |
| 393 | 358 |
| 394 void VideoCaptureImpl::OnDeviceFormatsInUseReceived( | 359 void VideoCaptureImpl::OnDeviceFormatsInUseReceived( |
| 395 const media::VideoCaptureFormats& formats_in_use) { | 360 const media::VideoCaptureFormats& formats_in_use) { |
| 396 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 361 DCHECK(thread_checker_.CalledOnValidThread()); |
| 397 for (size_t i = 0; i < device_formats_in_use_callback_queue_.size(); ++i) | 362 for (size_t i = 0; i < device_formats_in_use_cb_queue_.size(); ++i) |
| 398 device_formats_in_use_callback_queue_[i].Run(formats_in_use); | 363 device_formats_in_use_cb_queue_[i].Run(formats_in_use); |
| 399 device_formats_in_use_callback_queue_.clear(); | 364 device_formats_in_use_cb_queue_.clear(); |
| 400 } | 365 } |
| 401 | 366 |
| 402 void VideoCaptureImpl::OnDelegateAdded(int32 device_id) { | 367 void VideoCaptureImpl::OnDelegateAdded(int32 device_id) { |
| 368 DCHECK(thread_checker_.CalledOnValidThread()); |
| 403 DVLOG(1) << "OnDelegateAdded: device_id " << device_id; | 369 DVLOG(1) << "OnDelegateAdded: device_id " << device_id; |
| 404 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 405 | 370 |
| 406 device_id_ = device_id; | 371 device_id_ = device_id; |
| 407 for (ClientInfo::iterator it = clients_pending_on_filter_.begin(); | 372 for (ClientInfoMap::iterator it = clients_pending_on_filter_.begin(); |
| 408 it != clients_pending_on_filter_.end(); ) { | 373 it != clients_pending_on_filter_.end(); ) { |
| 409 media::VideoCapture::EventHandler* handler = it->first; | 374 int client_id = it->first; |
| 410 const media::VideoCaptureParams params = it->second; | 375 VideoCaptureStateUpdateCB state_update_cb = |
| 376 it->second.state_update_cb; |
| 377 VideoCaptureDeliverFrameCB deliver_frame_cb = |
| 378 it->second.deliver_frame_cb; |
| 379 const media::VideoCaptureParams params = it->second.params; |
| 411 clients_pending_on_filter_.erase(it++); | 380 clients_pending_on_filter_.erase(it++); |
| 412 StartCapture(handler, params); | 381 StartCapture(client_id, params, state_update_cb, |
| 382 deliver_frame_cb); |
| 413 } | 383 } |
| 414 } | 384 } |
| 415 | 385 |
| 416 void VideoCaptureImpl::StopDevice() { | 386 void VideoCaptureImpl::StopDevice() { |
| 417 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 387 DCHECK(thread_checker_.CalledOnValidThread()); |
| 418 | 388 |
| 419 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { | 389 if (state_ == VIDEO_CAPTURE_STATE_STARTED) { |
| 420 state_ = VIDEO_CAPTURE_STATE_STOPPING; | 390 state_ = VIDEO_CAPTURE_STATE_STOPPING; |
| 421 Send(new VideoCaptureHostMsg_Stop(device_id_)); | 391 Send(new VideoCaptureHostMsg_Stop(device_id_)); |
| 422 params_.requested_format.frame_size.SetSize(0, 0); | 392 params_.requested_format.frame_size.SetSize(0, 0); |
| 423 } | 393 } |
| 424 } | 394 } |
| 425 | 395 |
| 426 void VideoCaptureImpl::RestartCapture() { | 396 void VideoCaptureImpl::RestartCapture() { |
| 427 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 397 DCHECK(thread_checker_.CalledOnValidThread()); |
| 428 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED); | 398 DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED); |
| 429 | 399 |
| 430 int width = 0; | 400 int width = 0; |
| 431 int height = 0; | 401 int height = 0; |
| 432 for (ClientInfo::iterator it = clients_.begin(); | 402 clients_.insert(clients_pending_on_restart_.begin(), |
| 403 clients_pending_on_restart_.end()); |
| 404 clients_pending_on_restart_.clear(); |
| 405 for (ClientInfoMap::iterator it = clients_.begin(); |
| 433 it != clients_.end(); ++it) { | 406 it != clients_.end(); ++it) { |
| 434 width = std::max(width, it->second.requested_format.frame_size.width()); | 407 width = std::max(width, |
| 435 height = std::max(height, it->second.requested_format.frame_size.height()); | 408 it->second.params.requested_format.frame_size.width()); |
| 436 } | 409 height = std::max(height, |
| 437 for (ClientInfo::iterator it = clients_pending_on_restart_.begin(); | 410 it->second.params.requested_format.frame_size.height()); |
| 438 it != clients_pending_on_restart_.end(); ) { | |
| 439 width = std::max(width, it->second.requested_format.frame_size.width()); | |
| 440 height = std::max(height, it->second.requested_format.frame_size.height()); | |
| 441 clients_[it->first] = it->second; | |
| 442 clients_pending_on_restart_.erase(it++); | |
| 443 } | 411 } |
| 444 params_.requested_format.frame_size.SetSize(width, height); | 412 params_.requested_format.frame_size.SetSize(width, height); |
| 445 DVLOG(1) << "RestartCapture, " | 413 DVLOG(1) << "RestartCapture, " |
| 446 << params_.requested_format.frame_size.ToString(); | 414 << params_.requested_format.frame_size.ToString(); |
| 447 StartCaptureInternal(); | 415 StartCaptureInternal(); |
| 448 } | 416 } |
| 449 | 417 |
| 450 void VideoCaptureImpl::StartCaptureInternal() { | 418 void VideoCaptureImpl::StartCaptureInternal() { |
| 451 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | 419 DCHECK(thread_checker_.CalledOnValidThread()); |
| 452 DCHECK(device_id_); | 420 DCHECK(device_id_); |
| 453 | 421 |
| 454 Send(new VideoCaptureHostMsg_Start(device_id_, session_id_, params_)); | 422 Send(new VideoCaptureHostMsg_Start(device_id_, session_id_, params_)); |
| 455 state_ = VIDEO_CAPTURE_STATE_STARTED; | 423 state_ = VIDEO_CAPTURE_STATE_STARTED; |
| 456 } | 424 } |
| 457 | 425 |
| 458 void VideoCaptureImpl::Send(IPC::Message* message) { | 426 void VideoCaptureImpl::Send(IPC::Message* message) { |
| 459 io_message_loop_proxy_->PostTask(FROM_HERE, | 427 DCHECK(thread_checker_.CalledOnValidThread()); |
| 460 base::Bind(base::IgnoreResult(&VideoCaptureMessageFilter::Send), | 428 message_filter_->Send(message); |
| 461 message_filter_.get(), message)); | |
| 462 } | 429 } |
| 463 | 430 |
| 464 bool VideoCaptureImpl::RemoveClient( | 431 bool VideoCaptureImpl::RemoveClient(int client_id, ClientInfoMap* clients) { |
| 465 media::VideoCapture::EventHandler* handler, | 432 DCHECK(thread_checker_.CalledOnValidThread()); |
| 466 ClientInfo* clients) { | |
| 467 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread()); | |
| 468 bool found = false; | 433 bool found = false; |
| 469 | 434 |
| 470 ClientInfo::iterator it = clients->find(handler); | 435 ClientInfoMap::iterator it = clients->find(client_id); |
| 471 if (it != clients->end()) { | 436 if (it != clients->end()) { |
| 472 handler->OnStopped(this); | 437 it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED); |
| 473 handler->OnRemoved(this); | |
| 474 clients->erase(it); | 438 clients->erase(it); |
| 475 found = true; | 439 found = true; |
| 476 } | 440 } |
| 477 return found; | 441 return found; |
| 478 } | 442 } |
| 479 | 443 |
| 480 } // namespace content | 444 } // namespace content |
| OLD | NEW |