12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_host.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/browser_main_loop.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/media/media_stream_manager.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/browser/renderer_host/media/video_capture_manager.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/common/media/video_capture_messages.h" 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace content { 1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VideoCaptureHost::VideoCaptureHost(MediaStreamManager* media_stream_manager) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : BrowserMessageFilter(VideoCaptureMsgStart), 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) media_stream_manager_(media_stream_manager) { 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VideoCaptureHost::~VideoCaptureHost() {} 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VideoCaptureHost::OnChannelClosing() { 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Since the IPC sender is gone, close all requested VideoCaptureDevices. 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) for (EntryMap::iterator it = entries_.begin(); it != entries_.end(); ) { 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const base::WeakPtr<VideoCaptureController>& controller = it->second; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (controller) { 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VideoCaptureControllerID controller_id(it->first); 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) media_stream_manager_->video_capture_manager()->StopCaptureForClient( 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) controller.get(), controller_id, this, false); 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++it; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Remove the entry for this controller_id so that when the controller 3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) // is added, the controller will be notified to stop for this client 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // in DoControllerAddedOnIOThread. 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) entries_.erase(it++); 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void VideoCaptureHost::OnDestruct() const { 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::DeleteOnIOThread::Destruct(this); 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/////////////////////////////////////////////////////////////////////////////// 46 47// Implements VideoCaptureControllerEventHandler. 48void VideoCaptureHost::OnError(const VideoCaptureControllerID& controller_id) { 49 DVLOG(1) << "VideoCaptureHost::OnError"; 50 BrowserThread::PostTask( 51 BrowserThread::IO, FROM_HERE, 52 base::Bind(&VideoCaptureHost::DoHandleErrorOnIOThread, 53 this, controller_id)); 54} 55 56void VideoCaptureHost::OnBufferCreated( 57 const VideoCaptureControllerID& controller_id, 58 base::SharedMemoryHandle handle, 59 int length, 60 int buffer_id) { 61 BrowserThread::PostTask( 62 BrowserThread::IO, FROM_HERE, 63 base::Bind(&VideoCaptureHost::DoSendNewBufferOnIOThread, 64 this, controller_id, handle, length, buffer_id)); 65} 66 67void VideoCaptureHost::OnBufferDestroyed( 68 const VideoCaptureControllerID& controller_id, 69 int buffer_id) { 70 BrowserThread::PostTask( 71 BrowserThread::IO, FROM_HERE, 72 base::Bind(&VideoCaptureHost::DoSendFreeBufferOnIOThread, 73 this, controller_id, buffer_id)); 74} 75 76void VideoCaptureHost::OnBufferReady( 77 const VideoCaptureControllerID& controller_id, 78 int buffer_id, 79 const media::VideoCaptureFormat& frame_format, 80 const gfx::Rect& visible_rect, 81 base::TimeTicks timestamp) { 82 BrowserThread::PostTask( 83 BrowserThread::IO, 84 FROM_HERE, 85 base::Bind(&VideoCaptureHost::DoSendFilledBufferOnIOThread, 86 this, 87 controller_id, 88 buffer_id, 89 frame_format, 90 visible_rect, 91 timestamp)); 92} 93 94void VideoCaptureHost::OnMailboxBufferReady( 95 const VideoCaptureControllerID& controller_id, 96 int buffer_id, 97 const gpu::MailboxHolder& mailbox_holder, 98 const media::VideoCaptureFormat& frame_format, 99 base::TimeTicks timestamp) { 100 BrowserThread::PostTask( 101 BrowserThread::IO, 102 FROM_HERE, 103 base::Bind(&VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread, 104 this, 105 controller_id, 106 buffer_id, 107 mailbox_holder, 108 frame_format, 109 timestamp)); 110} 111 112void VideoCaptureHost::OnEnded(const VideoCaptureControllerID& controller_id) { 113 DVLOG(1) << "VideoCaptureHost::OnEnded"; 114 BrowserThread::PostTask( 115 BrowserThread::IO, FROM_HERE, 116 base::Bind(&VideoCaptureHost::DoEndedOnIOThread, this, controller_id)); 117} 118 119void VideoCaptureHost::DoSendNewBufferOnIOThread( 120 const VideoCaptureControllerID& controller_id, 121 base::SharedMemoryHandle handle, 122 int length, 123 int buffer_id) { 124 DCHECK_CURRENTLY_ON(BrowserThread::IO); 125 126 if (entries_.find(controller_id) == entries_.end()) 127 return; 128 129 Send(new VideoCaptureMsg_NewBuffer(controller_id.device_id, handle, 130 length, buffer_id)); 131} 132 133void VideoCaptureHost::DoSendFreeBufferOnIOThread( 134 const VideoCaptureControllerID& controller_id, 135 int buffer_id) { 136 DCHECK_CURRENTLY_ON(BrowserThread::IO); 137 138 if (entries_.find(controller_id) == entries_.end()) 139 return; 140 141 Send(new VideoCaptureMsg_FreeBuffer(controller_id.device_id, buffer_id)); 142} 143 144void VideoCaptureHost::DoSendFilledBufferOnIOThread( 145 const VideoCaptureControllerID& controller_id, 146 int buffer_id, 147 const media::VideoCaptureFormat& format, 148 const gfx::Rect& visible_rect, 149 base::TimeTicks timestamp) { 150 DCHECK_CURRENTLY_ON(BrowserThread::IO); 151 152 if (entries_.find(controller_id) == entries_.end()) 153 return; 154 155 Send(new VideoCaptureMsg_BufferReady( 156 controller_id.device_id, buffer_id, format, visible_rect, timestamp)); 157} 158 159void VideoCaptureHost::DoSendFilledMailboxBufferOnIOThread( 160 const VideoCaptureControllerID& controller_id, 161 int buffer_id, 162 const gpu::MailboxHolder& mailbox_holder, 163 const media::VideoCaptureFormat& format, 164 base::TimeTicks timestamp) { 165 DCHECK_CURRENTLY_ON(BrowserThread::IO); 166 167 if (entries_.find(controller_id) == entries_.end()) 168 return; 169 170 Send(new VideoCaptureMsg_MailboxBufferReady( 171 controller_id.device_id, buffer_id, mailbox_holder, format, timestamp)); 172} 173 174void VideoCaptureHost::DoHandleErrorOnIOThread( 175 const VideoCaptureControllerID& controller_id) { 176 DCHECK_CURRENTLY_ON(BrowserThread::IO); 177 178 if (entries_.find(controller_id) == entries_.end()) 179 return; 180 181 Send(new VideoCaptureMsg_StateChanged(controller_id.device_id, 182 VIDEO_CAPTURE_STATE_ERROR)); 183 DeleteVideoCaptureControllerOnIOThread(controller_id, true); 184} 185 186void VideoCaptureHost::DoEndedOnIOThread( 187 const VideoCaptureControllerID& controller_id) { 188 DCHECK_CURRENTLY_ON(BrowserThread::IO); 189 DVLOG(1) << "VideoCaptureHost::DoEndedOnIOThread"; 190 if (entries_.find(controller_id) == entries_.end()) 191 return; 192 193 Send(new VideoCaptureMsg_StateChanged(controller_id.device_id, 194 VIDEO_CAPTURE_STATE_ENDED)); 195 DeleteVideoCaptureControllerOnIOThread(controller_id, false); 196} 197 198/////////////////////////////////////////////////////////////////////////////// 199// IPC Messages handler. 200bool VideoCaptureHost::OnMessageReceived(const IPC::Message& message) { 201 bool handled = true; 202 IPC_BEGIN_MESSAGE_MAP(VideoCaptureHost, message) 203 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Start, OnStartCapture) 204 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Pause, OnPauseCapture) 205 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Resume, OnResumeCapture) 206 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, OnStopCapture) 207 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady, OnReceiveEmptyBuffer) 208 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceSupportedFormats, 209 OnGetDeviceSupportedFormats) 210 IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_GetDeviceFormatsInUse, 211 OnGetDeviceFormatsInUse) 212 IPC_MESSAGE_UNHANDLED(handled = false) 213 IPC_END_MESSAGE_MAP() 214 215 return handled; 216} 217 218void VideoCaptureHost::OnStartCapture(int device_id, 219 media::VideoCaptureSessionId session_id, 220 const media::VideoCaptureParams& params) { 221 DCHECK_CURRENTLY_ON(BrowserThread::IO); 222 DVLOG(1) << "VideoCaptureHost::OnStartCapture:" 223 << " session_id=" << session_id 224 << ", device_id=" << device_id 225 << ", format=" << params.requested_format.ToString() 226 << "@" << params.requested_format.frame_rate 227 << " (" << (params.resolution_change_policy == 228 media::RESOLUTION_POLICY_DYNAMIC_WITHIN_LIMIT ? 229 "variable" : "constant") 230 << ")"; 231 VideoCaptureControllerID controller_id(device_id); 232 if (entries_.find(controller_id) != entries_.end()) { 233 Send(new VideoCaptureMsg_StateChanged(device_id, 234 VIDEO_CAPTURE_STATE_ERROR)); 235 return; 236 } 237 238 entries_[controller_id] = base::WeakPtr<VideoCaptureController>(); 239 media_stream_manager_->video_capture_manager()->StartCaptureForClient( 240 session_id, 241 params, 242 PeerHandle(), 243 controller_id, 244 this, 245 base::Bind(&VideoCaptureHost::OnControllerAdded, this, device_id)); 246} 247 248void VideoCaptureHost::OnControllerAdded( 249 int device_id, 250 const base::WeakPtr<VideoCaptureController>& controller) { 251 BrowserThread::PostTask( 252 BrowserThread::IO, 253 FROM_HERE, 254 base::Bind(&VideoCaptureHost::DoControllerAddedOnIOThread, 255 this, 256 device_id, 257 controller)); 258} 259 260void VideoCaptureHost::DoControllerAddedOnIOThread( 261 int device_id, 262 const base::WeakPtr<VideoCaptureController>& controller) { 263 DCHECK_CURRENTLY_ON(BrowserThread::IO); 264 VideoCaptureControllerID controller_id(device_id); 265 EntryMap::iterator it = entries_.find(controller_id); 266 if (it == entries_.end()) { 267 if (controller) { 268 media_stream_manager_->video_capture_manager()->StopCaptureForClient( 269 controller.get(), controller_id, this, false); 270 } 271 return; 272 } 273 274 if (!controller) { 275 Send(new VideoCaptureMsg_StateChanged(device_id, 276 VIDEO_CAPTURE_STATE_ERROR)); 277 entries_.erase(controller_id); 278 return; 279 } 280 281 DCHECK(!it->second); 282 it->second = controller; 283} 284 285void VideoCaptureHost::OnStopCapture(int device_id) { 286 DCHECK_CURRENTLY_ON(BrowserThread::IO); 287 DVLOG(1) << "VideoCaptureHost::OnStopCapture, device_id " << device_id; 288 289 VideoCaptureControllerID controller_id(device_id); 290 291 Send(new VideoCaptureMsg_StateChanged(device_id, 292 VIDEO_CAPTURE_STATE_STOPPED)); 293 DeleteVideoCaptureControllerOnIOThread(controller_id, false); 294} 295 296void VideoCaptureHost::OnPauseCapture(int device_id) { 297 DCHECK_CURRENTLY_ON(BrowserThread::IO); 298 DVLOG(1) << "VideoCaptureHost::OnPauseCapture, device_id " << device_id; 299 300 VideoCaptureControllerID controller_id(device_id); 301 EntryMap::iterator it = entries_.find(controller_id); 302 if (it == entries_.end()) 303 return; 304 305 if (it->second) { 306 media_stream_manager_->video_capture_manager()->PauseCaptureForClient( 307 it->second.get(), controller_id, this); 308 } 309} 310 311void VideoCaptureHost::OnResumeCapture( 312 int device_id, 313 media::VideoCaptureSessionId session_id, 314 const media::VideoCaptureParams& params) { 315 DCHECK_CURRENTLY_ON(BrowserThread::IO); 316 DVLOG(1) << "VideoCaptureHost::OnResumeCapture, device_id " << device_id; 317 318 VideoCaptureControllerID controller_id(device_id); 319 EntryMap::iterator it = entries_.find(controller_id); 320 if (it == entries_.end()) 321 return; 322 323 if (it->second) { 324 media_stream_manager_->video_capture_manager()->ResumeCaptureForClient( 325 session_id, params, it->second.get(), controller_id, this); 326 } 327} 328 329void VideoCaptureHost::OnReceiveEmptyBuffer(int device_id, 330 int buffer_id, 331 uint32 sync_point) { 332 DCHECK_CURRENTLY_ON(BrowserThread::IO); 333 334 VideoCaptureControllerID controller_id(device_id); 335 EntryMap::iterator it = entries_.find(controller_id); 336 if (it != entries_.end()) { 337 const base::WeakPtr<VideoCaptureController>& controller = it->second; 338 if (controller) 339 controller->ReturnBuffer(controller_id, this, buffer_id, sync_point); 340 } 341} 342 343void VideoCaptureHost::OnGetDeviceSupportedFormats( 344 int device_id, 345 media::VideoCaptureSessionId capture_session_id) { 346 DCHECK_CURRENTLY_ON(BrowserThread::IO); 347 DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormats, capture_session_id " 348 << capture_session_id; 349 media::VideoCaptureFormats device_supported_formats; 350 if (!media_stream_manager_->video_capture_manager() 351 ->GetDeviceSupportedFormats(capture_session_id, 352 &device_supported_formats)) { 353 DLOG(WARNING) 354 << "Could not retrieve device supported formats for device_id=" 355 << device_id << " capture_session_id=" << capture_session_id; 356 } 357 Send(new VideoCaptureMsg_DeviceSupportedFormatsEnumerated( 358 device_id, device_supported_formats)); 359} 360 361void VideoCaptureHost::OnGetDeviceFormatsInUse( 362 int device_id, 363 media::VideoCaptureSessionId capture_session_id) { 364 DCHECK_CURRENTLY_ON(BrowserThread::IO); 365 DVLOG(1) << "VideoCaptureHost::OnGetDeviceFormatsInUse, capture_session_id " 366 << capture_session_id; 367 media::VideoCaptureFormats formats_in_use; 368 if (!media_stream_manager_->video_capture_manager()->GetDeviceFormatsInUse( 369 capture_session_id, &formats_in_use)) { 370 DVLOG(1) << "Could not retrieve device format(s) in use for device_id=" 371 << device_id << " capture_session_id=" << capture_session_id; 372 } 373 Send(new VideoCaptureMsg_DeviceFormatsInUseReceived(device_id, 374 formats_in_use)); 375} 376 377void VideoCaptureHost::DeleteVideoCaptureControllerOnIOThread( 378 const VideoCaptureControllerID& controller_id, bool on_error) { 379 DCHECK_CURRENTLY_ON(BrowserThread::IO); 380 381 EntryMap::iterator it = entries_.find(controller_id); 382 if (it == entries_.end()) 383 return; 384 385 if (it->second) { 386 media_stream_manager_->video_capture_manager()->StopCaptureForClient( 387 it->second.get(), controller_id, this, on_error); 388 } 389 entries_.erase(it); 390} 391 392} // namespace content 393