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