15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Implementation notes about interactions with VideoCaptureImpl. 65c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// How is VideoCaptureImpl used: 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// VideoCaptureImpl is an IO thread object while VideoCaptureImplManager 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// lives only on the render thread. It is only possible to access an 115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// object of VideoCaptureImpl via a task on the IO thread. 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// How is VideoCaptureImpl deleted: 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// A task is posted to the IO thread to delete a VideoCaptureImpl. 165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Immediately after that the pointer to it is dropped. This means no 175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// access to this VideoCaptureImpl object is possible on the render 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// thread. Also note that VideoCaptureImpl does not post task to itself. 195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// The use of Unretained: 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// We make sure deletion is the last task on the IO thread for a 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// VideoCaptureImpl object. This allows the use of Unretained() binding. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/renderer/media/video_capture_impl_manager.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind_helpers.h" 295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "content/child/child_process.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/renderer/media/video_capture_impl.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/renderer/media/video_capture_message_filter.h" 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/bind_to_current_loop.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureImplManager::VideoCaptureImplManager() 375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu : next_client_id_(0), 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu filter_(new VideoCaptureMessageFilter()), 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_factory_(this) { 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)VideoCaptureImplManager::~VideoCaptureImplManager() { 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (devices_.empty()) 455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Forcibly release all video capture resources. 475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (VideoCaptureDeviceMap::iterator it = devices_.begin(); 485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu it != devices_.end(); ++it) { 495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::DeInit, 535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl))); 545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&base::DeletePointer<VideoCaptureImpl>, 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl))); 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu devices_.clear(); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubase::Closure VideoCaptureImplManager::UseDevice( 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) media::VideoCaptureSessionId id) { 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = NULL; 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VideoCaptureDeviceMap::iterator it = devices_.find(id); 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (it == devices_.end()) { 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu impl = CreateVideoCaptureImplForTesting(id, filter_.get()); 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!impl) 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu impl = new VideoCaptureImpl(id, filter_.get()); 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu devices_[id] = std::make_pair(1, impl); 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::Init, 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl))); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++it->second.first; 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return base::Bind(&VideoCaptureImplManager::UnrefDevice, 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu weak_factory_.GetWeakPtr(), id); 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liubase::Closure VideoCaptureImplManager::StartCapture( 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu media::VideoCaptureSessionId id, 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const media::VideoCaptureParams& params, 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const VideoCaptureStateUpdateCB& state_update_cb, 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const VideoCaptureDeliverFrameCB& deliver_frame_cb) { 895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(thread_checker_.CalledOnValidThread()); 905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureDeviceMap::iterator it = devices_.find(id); 915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(it != devices_.end()); 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // This ID is used to identify a client of VideoCaptureImpl. 955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const int client_id = ++next_client_id_; 965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::StartCapture, 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl), 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu client_id, 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu params, 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu state_update_cb, 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu deliver_frame_cb)); 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return base::Bind(&VideoCaptureImplManager::StopCapture, 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu weak_factory_.GetWeakPtr(), 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu client_id, id); 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid VideoCaptureImplManager::GetDeviceSupportedFormats( 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu media::VideoCaptureSessionId id, 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const VideoCaptureDeviceFormatsCB& callback) { 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(thread_checker_.CalledOnValidThread()); 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureDeviceMap::iterator it = devices_.find(id); 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(it != devices_.end()); 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 1175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats, 1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl), callback)); 1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid VideoCaptureImplManager::GetDeviceFormatsInUse( 1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu media::VideoCaptureSessionId id, 1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const VideoCaptureDeviceFormatsCB& callback) { 1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(thread_checker_.CalledOnValidThread()); 1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureDeviceMap::iterator it = devices_.find(id); 1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(it != devices_.end()); 1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse, 1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl), callback)); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuVideoCaptureImpl* 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuVideoCaptureImplManager::CreateVideoCaptureImplForTesting( 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) media::VideoCaptureSessionId id, 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VideoCaptureMessageFilter* filter) const { 1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return NULL; 1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid VideoCaptureImplManager::StopCapture( 1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu int client_id, media::VideoCaptureSessionId id) { 1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(thread_checker_.CalledOnValidThread()); 1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureDeviceMap::iterator it = devices_.find(id); 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu DCHECK(it != devices_.end()); 1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::StopCapture, 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl), client_id)); 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureImplManager::UnrefDevice( 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) media::VideoCaptureSessionId id) { 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VideoCaptureDeviceMap::iterator it = devices_.find(id); 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(it != devices_.end()); 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Unref and destroy on the IO thread if there's no more client. 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(it->second.first); 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) --it->second.first; 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!it->second.first) { 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) devices_.erase(id); 1675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::DeInit, 1705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl))); 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&base::DeletePointer<VideoCaptureImpl>, 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl))); 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void VideoCaptureImplManager::SuspendDevices(bool suspend) { 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(thread_checker_.CalledOnValidThread()); 1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (VideoCaptureDeviceMap::iterator it = devices_.begin(); 1815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu it != devices_.end(); ++it) { 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu VideoCaptureImpl* impl = it->second.second; 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ChildProcess::current()->io_message_loop_proxy()->PostTask( 1845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu FROM_HERE, 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Bind(&VideoCaptureImpl::SuspendCapture, 1865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu base::Unretained(impl), suspend)); 1875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 191