Index: content/browser/renderer_host/media/in_process_buildable_video_capture_device.cc |
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/in_process_buildable_video_capture_device.cc |
similarity index 15% |
copy from content/browser/renderer_host/media/video_capture_manager.cc |
copy to content/browser/renderer_host/media/in_process_buildable_video_capture_device.cc |
index 2118857ecee7866c2e984854298eaee4c37e217e..f5b584411812cc9cc653bb0fb40567ede8dd03ed 100644 |
--- a/content/browser/renderer_host/media/video_capture_manager.cc |
+++ b/content/browser/renderer_host/media/in_process_buildable_video_capture_device.cc |
@@ -1,62 +1,36 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
emircan
2017/03/16 20:54:03
2017
chfremer
2017/03/16 22:02:29
Done.
|
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "content/browser/renderer_host/media/video_capture_manager.h" |
+#include "content/browser/renderer_host/media/in_process_buildable_video_capture_device.h" |
-#include <algorithm> |
-#include <set> |
-#include <utility> |
- |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/command_line.h" |
-#include "base/location.h" |
-#include "base/logging.h" |
-#include "base/memory/ptr_util.h" |
#include "base/metrics/histogram_macros.h" |
-#include "base/single_thread_task_runner.h" |
-#include "base/stl_util.h" |
#include "base/strings/stringprintf.h" |
-#include "base/task_runner_util.h" |
-#include "base/threading/sequenced_worker_pool.h" |
-#include "base/threading/thread_task_runner_handle.h" |
-#include "build/build_config.h" |
#include "content/browser/media/capture/desktop_capture_device_uma_types.h" |
#include "content/browser/media/capture/web_contents_video_capture_device.h" |
-#include "content/browser/media/media_internals.h" |
#include "content/browser/renderer_host/media/video_capture_controller.h" |
-#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" |
#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h" |
#include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/desktop_media_id.h" |
#include "content/public/common/media_stream_request.h" |
#include "media/base/bind_to_current_loop.h" |
-#include "media/base/media_switches.h" |
-#include "media/base/video_facing.h" |
#include "media/capture/video/video_capture_buffer_pool_impl.h" |
#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h" |
-#include "media/capture/video/video_capture_device.h" |
#include "media/capture/video/video_capture_device_client.h" |
-#include "media/capture/video/video_capture_device_factory.h" |
- |
-#if defined(ENABLE_SCREEN_CAPTURE) |
+#include "media/capture/video/video_frame_receiver.h" |
-#if BUILDFLAG(ENABLE_WEBRTC) && !defined(OS_ANDROID) |
+#if defined(ENABLE_SCREEN_CAPTURE) && !defined(OS_ANDROID) |
#include "content/browser/media/capture/desktop_capture_device.h" |
-#endif |
- |
#if defined(USE_AURA) |
#include "content/browser/media/capture/desktop_capture_device_aura.h" |
#endif |
+#endif |
-#if defined(OS_ANDROID) |
+#if defined(ENABLE_SCREEN_CAPTURE) && defined(OS_ANDROID) |
#include "content/browser/media/capture/screen_capture_device_android.h" |
#endif |
-#endif // defined(ENABLE_SCREEN_CAPTURE) |
- |
namespace { |
class VideoFrameConsumerFeedbackObserverOnTaskRunner |
@@ -80,49 +54,18 @@ class VideoFrameConsumerFeedbackObserverOnTaskRunner |
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
}; |
-// Compares two VideoCaptureFormat by checking smallest frame_size area, then |
-// by _largest_ frame_rate. Used to order a VideoCaptureFormats vector so that |
-// the first entry for a given resolution has the largest frame rate, as needed |
-// by the ConsolidateCaptureFormats() method. |
-bool IsCaptureFormatSmaller(const media::VideoCaptureFormat& format1, |
- const media::VideoCaptureFormat& format2) { |
- DCHECK(format1.frame_size.GetCheckedArea().IsValid()); |
- DCHECK(format2.frame_size.GetCheckedArea().IsValid()); |
- if (format1.frame_size.GetCheckedArea().ValueOrDefault(0) == |
- format2.frame_size.GetCheckedArea().ValueOrDefault(0)) { |
- return format1.frame_rate > format2.frame_rate; |
- } |
- return format1.frame_size.GetCheckedArea().ValueOrDefault(0) < |
- format2.frame_size.GetCheckedArea().ValueOrDefault(0); |
-} |
- |
-bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1, |
- const media::VideoCaptureFormat& format2) { |
- DCHECK(format1.frame_size.GetCheckedArea().IsValid()); |
- DCHECK(format2.frame_size.GetCheckedArea().IsValid()); |
- return format1.frame_size.GetCheckedArea().ValueOrDefault(0) == |
- format2.frame_size.GetCheckedArea().ValueOrDefault(0); |
+std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( |
+ const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { |
+ return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); |
} |
-// This function receives a list of capture formats, removes duplicated |
-// resolutions while keeping the highest frame rate for each, and forcing I420 |
-// pixel format. |
-void ConsolidateCaptureFormats(media::VideoCaptureFormats* formats) { |
- if (formats->empty()) |
- return; |
- std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller); |
- // Due to the ordering imposed, the largest frame_rate is kept while removing |
- // duplicated resolutions. |
- media::VideoCaptureFormats::iterator last = |
- std::unique(formats->begin(), formats->end(), IsCaptureFormatSizeEqual); |
- formats->erase(last, formats->end()); |
- // Mark all formats as I420, since this is what the renderer side will get |
- // anyhow: the actual pixel format is decided at the device level. |
- // Don't do this for Y16 format as it is handled separatelly. |
- for (auto& format : *formats) { |
- if (format.pixel_format != media::PIXEL_FORMAT_Y16) |
- format.pixel_format = media::PIXEL_FORMAT_I420; |
- } |
+void StopAndReleaseDeviceOnDeviceThread( |
+ media::VideoCaptureDevice* device, |
+ std::unique_ptr<content::Ownership> context_reference) { |
+ SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime"); |
+ device->StopAndDeAllocate(); |
+ DVLOG(3) << "StopAndReleaseDeviceOnDeviceThread"; |
+ delete device; |
} |
// The maximum number of video frame buffers in-flight at any one time. This |
@@ -135,540 +78,299 @@ const int kMaxNumberOfBuffers = 3; |
// http://crbug.com/460318 |
const int kMaxNumberOfBuffersForTabCapture = 10; |
-// Used for logging capture events. |
-// Elements in this enum should not be deleted or rearranged; the only |
-// permitted operation is to add new elements before NUM_VIDEO_CAPTURE_EVENT. |
-enum VideoCaptureEvent { |
- VIDEO_CAPTURE_START_CAPTURE = 0, |
- VIDEO_CAPTURE_STOP_CAPTURE_OK = 1, |
- VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR = 2, |
- VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE = 3, |
- VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB = 4, |
- NUM_VIDEO_CAPTURE_EVENT |
-}; |
- |
-void LogVideoCaptureEvent(VideoCaptureEvent event) { |
- UMA_HISTOGRAM_ENUMERATION("Media.VideoCaptureManager.Event", |
- event, |
- NUM_VIDEO_CAPTURE_EVENT); |
-} |
- |
-// Counter used for identifying a DeviceRequest to start a capture device. |
-static int g_device_start_id = 0; |
- |
-const media::VideoCaptureSessionId kFakeSessionId = -1; |
- |
-std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder( |
- const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) { |
- return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb); |
-} |
- |
-} // namespace |
+} // anonymous namespace |
namespace content { |
-// Instances of this struct go through several different phases during their |
-// lifetime. |
-// Phase 1: When first created (in GetOrCreateDeviceEntry()), this consists of |
-// only the |video_capture_controller|. Clients can already connect to the |
-// controller, but there is no |video_capture_device| present. |
-// Phase 2: When a request to "start" the entry comes in (via |
-// HandleQueuedStartRequest()), creation of |video_capture_device| is scheduled |
-// to run asynchronously on the Device Thread. |
-// Phase 3: As soon as the creation of the VideoCaptureDevice is complete, this |
-// newly created VideoCaptureDevice instance is connected to the |
-// VideoCaptureController via SetConsumerFeedbackObserver(). |
-// Phase 4: This phase can only be reached on Android. When the application goes |
-// to the background, the |video_capture_device| is asynchronously stopped and |
-// released on the Device Thread. When the application is resumed, we |
-// transition to Phase 2. |
-struct VideoCaptureManager::DeviceEntry { |
- public: |
- DeviceEntry(MediaStreamType stream_type, |
- const std::string& id, |
- const media::VideoCaptureParams& params); |
- ~DeviceEntry(); |
- std::unique_ptr<media::VideoCaptureDevice::Client> CreateDeviceClient(); |
- |
- const int serial_id; |
- const MediaStreamType stream_type; |
- const std::string id; |
- const media::VideoCaptureParams parameters; |
- VideoCaptureController video_capture_controller; |
- std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
-}; |
- |
-// Bundles a media::VideoCaptureDeviceDescriptor with corresponding supported |
-// video formats. |
-struct VideoCaptureManager::DeviceInfo { |
- DeviceInfo(); |
- DeviceInfo(media::VideoCaptureDeviceDescriptor descriptor); |
- DeviceInfo(const DeviceInfo& other); |
- ~DeviceInfo(); |
- DeviceInfo& operator=(const DeviceInfo& other); |
- |
- media::VideoCaptureDeviceDescriptor descriptor; |
- media::VideoCaptureFormats supported_formats; |
-}; |
- |
-// Class used for queuing request for starting a device. |
-class VideoCaptureManager::CaptureDeviceStartRequest { |
- public: |
- CaptureDeviceStartRequest(int serial_id, |
- media::VideoCaptureSessionId session_id, |
- const media::VideoCaptureParams& params); |
- int serial_id() const { return serial_id_; } |
- media::VideoCaptureSessionId session_id() const { return session_id_; } |
- media::VideoCaptureParams params() const { return params_; } |
- |
- // Set to true if the device should be stopped before it has successfully |
- // been started. |
- bool abort_start() const { return abort_start_; } |
- void set_abort_start() { abort_start_ = true; } |
- |
- private: |
- const int serial_id_; |
- const media::VideoCaptureSessionId session_id_; |
- const media::VideoCaptureParams params_; |
- // Set to true if the device should be stopped before it has successfully |
- // been started. |
- bool abort_start_; |
-}; |
- |
-VideoCaptureManager::DeviceEntry::DeviceEntry( |
- MediaStreamType stream_type, |
- const std::string& id, |
- const media::VideoCaptureParams& params) |
- : serial_id(g_device_start_id++), |
- stream_type(stream_type), |
- id(id), |
- parameters(params) {} |
+InProcessBuildableVideoCaptureDevice::InProcessBuildableVideoCaptureDevice( |
+ scoped_refptr<base::SingleThreadTaskRunner> device_task_runner, |
+ media::VideoCaptureDeviceFactory* device_factory) |
+ : device_task_runner_(std::move(device_task_runner)), |
+ device_factory_(device_factory) {} |
-VideoCaptureManager::DeviceEntry::~DeviceEntry() { |
+InProcessBuildableVideoCaptureDevice::~InProcessBuildableVideoCaptureDevice() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // DCHECK that this DeviceEntry does not still own a |
- // media::VideoCaptureDevice. media::VideoCaptureDevice must be deleted on |
- // the device thread. |
- DCHECK(video_capture_device == nullptr); |
+ DCHECK(!device_); |
} |
-std::unique_ptr<media::VideoCaptureDevice::Client> |
-VideoCaptureManager::DeviceEntry::CreateDeviceClient() { |
+void InProcessBuildableVideoCaptureDevice::CreateAndStartDeviceAsync( |
+ VideoCaptureController* entry, |
+ VideoCaptureController* controller, |
+ const media::VideoCaptureParams& params, |
+ BuildableDeviceCallbacks* callbacks, |
+ std::unique_ptr<Ownership> context_reference) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- const int max_buffers = stream_type == MEDIA_TAB_VIDEO_CAPTURE |
- ? kMaxNumberOfBuffersForTabCapture |
- : kMaxNumberOfBuffers; |
- scoped_refptr<media::VideoCaptureBufferPool> buffer_pool = |
- new media::VideoCaptureBufferPoolImpl( |
- base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
- max_buffers); |
- |
- return base::MakeUnique<media::VideoCaptureDeviceClient>( |
- base::MakeUnique<VideoFrameReceiverOnIOThread>( |
- video_capture_controller.GetWeakPtrForIOThread()), |
- std::move(buffer_pool), |
- base::Bind(&CreateGpuJpegDecoder, |
- base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, |
- video_capture_controller.GetWeakPtrForIOThread()))); |
-} |
- |
-VideoCaptureManager::DeviceInfo::DeviceInfo() = default; |
+ const int max_buffers = (entry->stream_type() == MEDIA_TAB_VIDEO_CAPTURE |
+ ? kMaxNumberOfBuffersForTabCapture |
+ : kMaxNumberOfBuffers); |
-VideoCaptureManager::DeviceInfo::DeviceInfo( |
- media::VideoCaptureDeviceDescriptor descriptor) |
- : descriptor(descriptor) {} |
+ auto device_client = |
+ CreateDeviceClient(max_buffers, controller->GetWeakPtrForIOThread()); |
-VideoCaptureManager::DeviceInfo::DeviceInfo( |
- const VideoCaptureManager::DeviceInfo& other) = default; |
+ base::Closure start_capture_closure; |
+ // Use of |this| is safe, because |context_reference| guarantees that |this| |
emircan
2017/03/16 20:54:03
s/Use of |this| is safe/Use of Unretained() is saf
chfremer
2017/03/16 22:02:29
Done.
|
+ // stays alive. |
+ ReceiveDeviceCallback after_start_capture_callback = media::BindToCurrentLoop( |
+ base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
+ base::Unretained(this), entry, controller, callbacks, |
+ base::Passed(&context_reference))); |
-VideoCaptureManager::DeviceInfo::~DeviceInfo() = default; |
- |
-VideoCaptureManager::DeviceInfo& VideoCaptureManager::DeviceInfo::operator=( |
- const VideoCaptureManager::DeviceInfo& other) = default; |
+ switch (entry->stream_type()) { |
+ case MEDIA_DEVICE_VIDEO_CAPTURE: { |
+ const media::VideoCaptureDeviceDescriptor* descriptor = |
+ callbacks->LookupDeviceDescriptor(entry->device_id()); |
+ if (descriptor) { |
+ controller->OnLog( |
+ base::StringPrintf("Starting device: id: %s, name: %s, api: %s", |
+ descriptor->device_id.c_str(), |
+ descriptor->GetNameAndModel().c_str(), |
+ descriptor->GetCaptureApiTypeString())); |
+ |
+ callbacks->WillStartDevice(descriptor->facing); |
+ |
+ start_capture_closure = |
+ base::Bind(&InProcessBuildableVideoCaptureDevice:: |
+ DoStartDeviceCaptureOnDeviceThread, |
+ base::Unretained(this), *descriptor, params, |
+ base::Passed(std::move(device_client)), |
+ std::move(after_start_capture_callback)); |
+ } else { |
+ callbacks->OnDeviceStartFailed(entry); |
+ return; |
+ } |
+ break; |
+ } |
+ case MEDIA_TAB_VIDEO_CAPTURE: |
+ start_capture_closure = |
+ base::Bind(&InProcessBuildableVideoCaptureDevice:: |
+ DoStartTabCaptureOnDeviceThread, |
+ base::Unretained(this), entry->device_id(), params, |
+ base::Passed(std::move(device_client)), |
+ std::move(after_start_capture_callback)); |
+ break; |
-VideoCaptureManager::CaptureDeviceStartRequest::CaptureDeviceStartRequest( |
- int serial_id, |
- media::VideoCaptureSessionId session_id, |
- const media::VideoCaptureParams& params) |
- : serial_id_(serial_id), |
- session_id_(session_id), |
- params_(params), |
- abort_start_(false) { |
-} |
+ case MEDIA_DESKTOP_VIDEO_CAPTURE: |
+ start_capture_closure = |
+ base::Bind(&InProcessBuildableVideoCaptureDevice:: |
+ DoStartDesktopCaptureOnDeviceThread, |
+ base::Unretained(this), entry->device_id(), params, |
+ base::Passed(std::move(device_client)), |
+ std::move(after_start_capture_callback)); |
+ break; |
-VideoCaptureManager::VideoCaptureManager( |
- std::unique_ptr<media::VideoCaptureDeviceFactory> factory, |
- scoped_refptr<base::SingleThreadTaskRunner> device_task_runner) |
- : device_task_runner_(std::move(device_task_runner)), |
- new_capture_session_id_(1), |
- video_capture_device_factory_(std::move(factory)) {} |
+ default: { |
+ NOTIMPLEMENTED(); |
+ return; |
+ } |
+ } |
-VideoCaptureManager::~VideoCaptureManager() { |
- DCHECK(devices_.empty()); |
- DCHECK(device_start_queue_.empty()); |
+ device_task_runner_->PostTask(FROM_HERE, start_capture_closure); |
} |
-void VideoCaptureManager::AddVideoCaptureObserver( |
- media::VideoCaptureObserver* observer) { |
- DCHECK(observer); |
+void InProcessBuildableVideoCaptureDevice::ReleaseDeviceAsync( |
+ VideoCaptureController* controller, |
+ std::unique_ptr<Ownership>) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- capture_observers_.AddObserver(observer); |
+ controller->SetConsumerFeedbackObserver(nullptr); |
+ if (!device_) |
+ return; |
+ media::VideoCaptureDevice* device_ptr = device_.release(); |
+ auto device_task_runner_context_reference = |
+ MakeScopedRefptrOwnership(device_task_runner_); |
+ bool posting_task_succeeded = device_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&StopAndReleaseDeviceOnDeviceThread, device_ptr, |
+ base::Passed(&device_task_runner_context_reference))); |
+ if (posting_task_succeeded == false) { |
+ // Since posting to the task runner has failed, we attempt doing it on |
+ // the calling thread instead. |
+ StopAndReleaseDeviceOnDeviceThread(device_ptr, nullptr); |
+ } |
} |
-void VideoCaptureManager::RemoveAllVideoCaptureObservers() { |
+bool InProcessBuildableVideoCaptureDevice::IsDeviceAlive() const { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- capture_observers_.Clear(); |
+ return device_ != nullptr; |
} |
-void VideoCaptureManager::RegisterListener( |
- MediaStreamProviderListener* listener) { |
+void InProcessBuildableVideoCaptureDevice::GetPhotoCapabilities( |
+ media::VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) const { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(listener); |
- DCHECK(device_task_runner_); |
- listeners_.AddObserver(listener); |
-#if defined(OS_ANDROID) |
- application_state_has_running_activities_ = true; |
- app_status_listener_.reset(new base::android::ApplicationStatusListener( |
- base::Bind(&VideoCaptureManager::OnApplicationStateChange, |
- base::Unretained(this)))); |
-#endif |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
+ device_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&media::VideoCaptureDevice::GetPhotoCapabilities, |
+ base::Unretained(device_.get()), base::Passed(&callback))); |
} |
-void VideoCaptureManager::UnregisterListener( |
- MediaStreamProviderListener* listener) { |
+void InProcessBuildableVideoCaptureDevice::SetPhotoOptions( |
+ media::mojom::PhotoSettingsPtr settings, |
+ media::VideoCaptureDevice::SetPhotoOptionsCallback callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- listeners_.RemoveObserver(listener); |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
+ device_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&media::VideoCaptureDevice::SetPhotoOptions, |
+ base::Unretained(device_.get()), |
+ base::Passed(&settings), base::Passed(&callback))); |
} |
-void VideoCaptureManager::EnumerateDevices( |
- const EnumerationCallback& client_callback) { |
+void InProcessBuildableVideoCaptureDevice::TakePhoto( |
+ media::VideoCaptureDevice::TakePhotoCallback callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DVLOG(1) << "VideoCaptureManager::EnumerateDevices"; |
- |
- // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument |
- // for another callback to OnDevicesInfoEnumerated() to be run in the current |
- // loop, i.e. IO loop. Pass a timer for UMA histogram collection. |
- base::Callback<void(std::unique_ptr<VideoCaptureDeviceDescriptors>)> |
- devices_enumerated_callback = base::Bind( |
- &VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread, this, |
- media::BindToCurrentLoop(base::Bind( |
- &VideoCaptureManager::OnDevicesInfoEnumerated, this, |
- base::Owned(new base::ElapsedTimer()), client_callback)), |
- devices_info_cache_); |
- // OK to use base::Unretained() since we own the VCDFactory and |this| is |
- // bound in |devices_enumerated_callback|. |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
device_task_runner_->PostTask( |
FROM_HERE, |
- base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceDescriptors, |
- base::Unretained(video_capture_device_factory_.get()), |
- devices_enumerated_callback)); |
+ base::Bind(&media::VideoCaptureDevice::TakePhoto, |
+ base::Unretained(device_.get()), base::Passed(&callback))); |
} |
-int VideoCaptureManager::Open(const MediaStreamDevice& device) { |
+void InProcessBuildableVideoCaptureDevice::MaybeSuspendDevice() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- // Generate a new id for the session being opened. |
- const media::VideoCaptureSessionId capture_session_id = |
- new_capture_session_id_++; |
- |
- DCHECK(sessions_.find(capture_session_id) == sessions_.end()); |
- DVLOG(1) << "VideoCaptureManager::Open, id " << capture_session_id; |
- |
- // We just save the stream info for processing later. |
- sessions_[capture_session_id] = device; |
- |
- // Notify our listener asynchronously; this ensures that we return |
- // |capture_session_id| to the caller of this function before using that same |
- // id in a listener event. |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(&VideoCaptureManager::OnOpened, this, device.type, |
- capture_session_id)); |
- return capture_session_id; |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
+ device_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&media::VideoCaptureDevice::MaybeSuspend, |
+ base::Unretained(device_.get()))); |
} |
-void VideoCaptureManager::Close(int capture_session_id) { |
+void InProcessBuildableVideoCaptureDevice::ResumeDevice() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id; |
- |
- SessionMap::iterator session_it = sessions_.find(capture_session_id); |
- if (session_it == sessions_.end()) { |
- NOTREACHED(); |
- return; |
- } |
- |
- DeviceEntry* const existing_device = |
- GetDeviceEntryByTypeAndId(session_it->second.type, session_it->second.id); |
- if (existing_device) { |
- // Remove any client that is still using the session. This is safe to call |
- // even if there are no clients using the session. |
- existing_device->video_capture_controller.StopSession(capture_session_id); |
- |
- // StopSession() may have removed the last client, so we might need to |
- // close the device. |
- DestroyDeviceEntryIfNoClients(existing_device); |
- } |
- |
- // Notify listeners asynchronously, and forget the session. |
- base::ThreadTaskRunnerHandle::Get()->PostTask( |
- FROM_HERE, base::Bind(&VideoCaptureManager::OnClosed, this, |
- session_it->second.type, capture_session_id)); |
- sessions_.erase(session_it); |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
+ device_task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&media::VideoCaptureDevice::Resume, |
+ base::Unretained(device_.get()))); |
} |
-void VideoCaptureManager::QueueStartDevice( |
- media::VideoCaptureSessionId session_id, |
- DeviceEntry* entry, |
- const media::VideoCaptureParams& params) { |
+void InProcessBuildableVideoCaptureDevice::RequestRefreshFrame() { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- device_start_queue_.push_back( |
- CaptureDeviceStartRequest(entry->serial_id, session_id, params)); |
- if (device_start_queue_.size() == 1) |
- HandleQueuedStartRequest(); |
+ // Unretained() is safe to use here because |device| would be null if it |
+ // was scheduled for shutdown and destruction, and because this task is |
+ // guaranteed to run before the task that destroys the |device|. |
+ device_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame, |
+ base::Unretained(device_.get()))); |
} |
-void VideoCaptureManager::DoStopDevice(DeviceEntry* entry) { |
+void InProcessBuildableVideoCaptureDevice::SetDesktopCaptureWindowIdAsync( |
+ gfx::NativeViewId window_id, |
+ std::unique_ptr<Ownership> context_reference) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // TODO(mcasas): use a helper function https://crbug.com/624854. |
- DCHECK( |
- std::find_if(devices_.begin(), devices_.end(), |
- [entry](const std::unique_ptr<DeviceEntry>& device_entry) { |
- return device_entry.get() == entry; |
- }) != devices_.end()); |
- |
- // Find the matching start request. |
- for (DeviceStartQueue::reverse_iterator request = |
- device_start_queue_.rbegin(); |
- request != device_start_queue_.rend(); ++request) { |
- if (request->serial_id() == entry->serial_id) { |
- request->set_abort_start(); |
- DVLOG(3) << "DoStopDevice, aborting start request for device " |
- << entry->id << " serial_id = " << entry->serial_id; |
- return; |
- } |
- } |
- |
- const DeviceInfo* device_info = GetDeviceInfoById(entry->id); |
- if (device_info != nullptr) { |
- for (auto& observer : capture_observers_) |
- observer.OnVideoCaptureStopped(device_info->descriptor.facing); |
- } |
- |
- DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id |
- << " serial_id = " << entry->serial_id << "."; |
- entry->video_capture_controller.OnLog( |
- base::StringPrintf("Stopping device: id: %s", entry->id.c_str())); |
- entry->video_capture_controller.SetConsumerFeedbackObserver(nullptr); |
- |
- // |entry->video_capture_device| can be null if creating the device has |
- // failed. |
- if (entry->video_capture_device) { |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, |
- base::Passed(&entry->video_capture_device))); |
- } |
+ // Post |device_| to the the device_task_runner_. This is safe since the |
+ // device is destroyed on the device_task_runner_ and |context_reference| |
+ // guarantees that |this| stays alive. |
+ device_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&InProcessBuildableVideoCaptureDevice:: |
+ SetDesktopCaptureWindowIdOnDeviceThread, |
+ base::Unretained(this), device_.get(), window_id, |
+ base::Passed(&context_reference))); |
} |
-void VideoCaptureManager::HandleQueuedStartRequest() { |
+std::unique_ptr<media::VideoCaptureDeviceClient> |
+InProcessBuildableVideoCaptureDevice::CreateDeviceClient( |
+ int buffer_pool_max_buffer_count, |
+ base::WeakPtr<media::VideoFrameReceiver> receiver) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // Remove all start requests that have been aborted. |
- while (device_start_queue_.begin() != device_start_queue_.end() && |
- device_start_queue_.begin()->abort_start()) { |
- device_start_queue_.pop_front(); |
- } |
- DeviceStartQueue::iterator request = device_start_queue_.begin(); |
- if (request == device_start_queue_.end()) |
- return; |
- const int serial_id = request->serial_id(); |
- DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); |
- DCHECK(entry); |
- |
- DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = " |
- << entry->id << " start id = " << entry->serial_id; |
- |
- std::unique_ptr<media::VideoCaptureDevice::Client> device_client = |
- entry->CreateDeviceClient(); |
- |
- base::Callback<std::unique_ptr<VideoCaptureDevice>(void)> |
- start_capture_function; |
- |
- switch (entry->stream_type) { |
- case MEDIA_DEVICE_VIDEO_CAPTURE: { |
- // We look up the device id from the renderer in our local enumeration |
- // since the renderer does not have all the information that might be |
- // held in the browser-side VideoCaptureDevice::Name structure. |
- const DeviceInfo* found = GetDeviceInfoById(entry->id); |
- if (found) { |
- entry->video_capture_controller.OnLog( |
- base::StringPrintf("Starting device: id: %s, name: %s, api: %s", |
- found->descriptor.device_id.c_str(), |
- found->descriptor.GetNameAndModel().c_str(), |
- found->descriptor.GetCaptureApiTypeString())); |
- |
- for (auto& observer : capture_observers_) |
- observer.OnVideoCaptureStarted(found->descriptor.facing); |
- |
- start_capture_function = |
- base::Bind(&VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread, |
- this, found->descriptor, request->params(), |
- base::Passed(std::move(device_client))); |
- } else { |
- // Errors from DoStartDeviceCaptureOnDeviceThread go via |
- // VideoCaptureDeviceClient::OnError, which needs some thread |
- // dancing to get errors processed on the IO thread. But since |
- // we're on that thread, we call VideoCaptureController |
- // methods directly. |
- const std::string log_message = base::StringPrintf( |
- "Error on %s:%d: device %s unknown. Maybe recently disconnected?", |
- __FILE__, __LINE__, entry->id.c_str()); |
- DLOG(ERROR) << log_message; |
- entry->video_capture_controller.OnLog(log_message); |
- entry->video_capture_controller.OnError(); |
- // Drop the failed start request. |
- device_start_queue_.pop_front(); |
- |
- return; |
- } |
- break; |
- } |
- case MEDIA_TAB_VIDEO_CAPTURE: |
- start_capture_function = base::Bind( |
- &VideoCaptureManager::DoStartTabCaptureOnDeviceThread, this, |
- entry->id, request->params(), base::Passed(std::move(device_client))); |
- break; |
- |
- case MEDIA_DESKTOP_VIDEO_CAPTURE: |
- start_capture_function = base::Bind( |
- &VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread, this, |
- entry->id, request->params(), base::Passed(std::move(device_client))); |
- break; |
+ scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_ = |
+ new media::VideoCaptureBufferPoolImpl( |
+ base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
+ buffer_pool_max_buffer_count); |
- default: { |
- NOTIMPLEMENTED(); |
- return; |
- } |
- } |
- base::PostTaskAndReplyWithResult( |
- device_task_runner_.get(), FROM_HERE, start_capture_function, |
- base::Bind(&VideoCaptureManager::OnDeviceStarted, this, |
- request->serial_id())); |
+ return base::MakeUnique<media::VideoCaptureDeviceClient>( |
+ base::MakeUnique<VideoFrameReceiverOnIOThread>(receiver), buffer_pool_, |
+ base::Bind(&CreateGpuJpegDecoder, |
+ base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, |
+ receiver))); |
} |
-void VideoCaptureManager::OnDeviceStarted( |
- int serial_id, |
- std::unique_ptr<VideoCaptureDevice> device) { |
- DVLOG(3) << __func__; |
+void InProcessBuildableVideoCaptureDevice::OnDeviceStarted( |
+ VideoCaptureController* entry, |
+ VideoCaptureController* controller, |
+ BuildableDeviceCallbacks* callbacks, |
+ std::unique_ptr<Ownership> context_reference, |
+ std::unique_ptr<media::VideoCaptureDevice> device) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK_EQ(serial_id, device_start_queue_.begin()->serial_id()); |
- // |device| can be null if creation failed in |
- // DoStartDeviceCaptureOnDeviceThread. |
- if (device_start_queue_.front().abort_start()) { |
- // The device is no longer wanted. Stop the device again. |
- DVLOG(3) << "OnDeviceStarted but start request have been aborted."; |
- media::VideoCaptureDevice* device_ptr = device.get(); |
- base::Closure closure = |
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this, |
- base::Passed(&device)); |
- if (device_ptr && !device_task_runner_->PostTask(FROM_HERE, closure)) { |
- // PostTask failed. The device must be stopped anyway. |
- device_ptr->StopAndDeAllocate(); |
- } |
- } else { |
- DeviceEntry* const entry = GetDeviceEntryBySerialId(serial_id); |
- DCHECK(entry); |
- DCHECK(!entry->video_capture_device); |
- if (device) { |
- // Passing raw pointer |device.get()| to the controller is safe, |
- // because we transfer ownership of it to |entry|. We are calling |
- // SetConsumerFeedbackObserver(nullptr) before releasing |
- // |entry->video_capture_device_| on the |device_task_runner_|. |
- entry->video_capture_controller.SetConsumerFeedbackObserver( |
- base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( |
- device.get(), device_task_runner_)); |
- } |
- entry->video_capture_device = std::move(device); |
- |
- if (entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE) { |
- const media::VideoCaptureSessionId session_id = |
- device_start_queue_.front().session_id(); |
- DCHECK(session_id != kFakeSessionId); |
- MaybePostDesktopCaptureWindowId(session_id); |
- } |
- |
- auto it = photo_request_queue_.begin(); |
- while (it != photo_request_queue_.end()) { |
- auto request = it++; |
- DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first); |
- if (maybe_entry && maybe_entry->video_capture_device) { |
- request->second.Run(maybe_entry->video_capture_device.get()); |
- photo_request_queue_.erase(request); |
- } |
- } |
+ if (!device) { |
+ callbacks->OnDeviceStartFailed(entry); |
+ return; |
} |
- |
- device_start_queue_.pop_front(); |
- HandleQueuedStartRequest(); |
+ // Passing raw pointer |device.get()| to the controller is safe, |
+ // because we take ownership of |device| and we call |
+ // controller->SetConsumerFeedbackObserver(nullptr) before releasing |device|. |
+ controller->SetConsumerFeedbackObserver( |
+ base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( |
+ device.get(), device_task_runner_)); |
+ device_ = std::move(device); |
+ callbacks->DidStartDevice(entry); |
} |
-std::unique_ptr<media::VideoCaptureDevice> |
-VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread( |
- const VideoCaptureDeviceDescriptor& descriptor, |
+void InProcessBuildableVideoCaptureDevice::DoStartDeviceCaptureOnDeviceThread( |
+ const media::VideoCaptureDeviceDescriptor& descriptor, |
const media::VideoCaptureParams& params, |
- std::unique_ptr<VideoCaptureDevice::Client> device_client) { |
+ std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
+ ReceiveDeviceCallback result_callback) { |
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
- DCHECK(IsOnDeviceThread()); |
+ DCHECK(device_task_runner_->BelongsToCurrentThread()); |
- std::unique_ptr<VideoCaptureDevice> video_capture_device; |
- video_capture_device = |
- video_capture_device_factory_->CreateDevice(descriptor); |
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device = |
+ device_factory_->CreateDevice(descriptor); |
if (!video_capture_device) { |
- device_client->OnError(FROM_HERE, "Could not create capture device"); |
- return nullptr; |
+ result_callback.Run(nullptr); |
+ return; |
} |
video_capture_device->AllocateAndStart(params, std::move(device_client)); |
- return video_capture_device; |
+ result_callback.Run(std::move(video_capture_device)); |
} |
-std::unique_ptr<media::VideoCaptureDevice> |
-VideoCaptureManager::DoStartTabCaptureOnDeviceThread( |
+void InProcessBuildableVideoCaptureDevice::DoStartTabCaptureOnDeviceThread( |
const std::string& id, |
const media::VideoCaptureParams& params, |
- std::unique_ptr<VideoCaptureDevice::Client> device_client) { |
+ std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
+ ReceiveDeviceCallback result_callback) { |
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
- DCHECK(IsOnDeviceThread()); |
+ DCHECK(device_task_runner_->BelongsToCurrentThread()); |
- std::unique_ptr<VideoCaptureDevice> video_capture_device; |
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
#endif |
if (!video_capture_device) { |
- device_client->OnError(FROM_HERE, "Could not create capture device"); |
- return nullptr; |
+ result_callback.Run(nullptr); |
+ return; |
} |
video_capture_device->AllocateAndStart(params, std::move(device_client)); |
- return video_capture_device; |
+ result_callback.Run(std::move(video_capture_device)); |
} |
-std::unique_ptr<media::VideoCaptureDevice> |
-VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread( |
+void InProcessBuildableVideoCaptureDevice::DoStartDesktopCaptureOnDeviceThread( |
const std::string& id, |
const media::VideoCaptureParams& params, |
- std::unique_ptr<VideoCaptureDevice::Client> device_client) { |
+ std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
+ ReceiveDeviceCallback result_callback) { |
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
- DCHECK(IsOnDeviceThread()); |
+ DCHECK(device_task_runner_->BelongsToCurrentThread()); |
- std::unique_ptr<VideoCaptureDevice> video_capture_device; |
+ std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
#if defined(ENABLE_SCREEN_CAPTURE) |
DesktopMediaID desktop_id = DesktopMediaID::Parse(id); |
if (desktop_id.is_null()) { |
- device_client->OnError(FROM_HERE, "Desktop media ID is null"); |
- return nullptr; |
+ DLOG(ERROR) << "Desktop media ID is null"; |
+ result_callback.Run(nullptr); |
+ return; |
} |
if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { |
@@ -689,544 +391,30 @@ VideoCaptureManager::DoStartDesktopCaptureOnDeviceThread( |
video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); |
#endif // defined(USE_AURA) |
#if BUILDFLAG(ENABLE_WEBRTC) |
- if (!video_capture_device) |
- video_capture_device = DesktopCaptureDevice::Create(desktop_id); |
+ if (!video_capture_device) |
+ video_capture_device = DesktopCaptureDevice::Create(desktop_id); |
#endif // BUILDFLAG(ENABLE_WEBRTC) |
#endif // defined (OS_ANDROID) |
} |
#endif // defined(ENABLE_SCREEN_CAPTURE) |
if (!video_capture_device) { |
- device_client->OnError(FROM_HERE, "Could not create capture device"); |
- return nullptr; |
- } |
- |
- video_capture_device->AllocateAndStart(params, std::move(device_client)); |
- return video_capture_device; |
-} |
- |
-void VideoCaptureManager::StartCaptureForClient( |
- media::VideoCaptureSessionId session_id, |
- const media::VideoCaptureParams& params, |
- VideoCaptureControllerID client_id, |
- VideoCaptureControllerEventHandler* client_handler, |
- const DoneCB& done_cb) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DVLOG(1) << __func__ << ", session_id = " << session_id << ", request: " |
- << media::VideoCaptureFormat::ToString(params.requested_format); |
- |
- DeviceEntry* entry = GetOrCreateDeviceEntry(session_id, params); |
- if (!entry) { |
- done_cb.Run(base::WeakPtr<VideoCaptureController>()); |
+ result_callback.Run(nullptr); |
return; |
} |
- LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE); |
- |
- // First client starts the device. |
- if (!entry->video_capture_controller.HasActiveClient() && |
- !entry->video_capture_controller.HasPausedClient()) { |
- DVLOG(1) << "VideoCaptureManager starting device (type = " |
- << entry->stream_type << ", id = " << entry->id << ")"; |
- QueueStartDevice(session_id, entry, params); |
- } |
- // Run the callback first, as AddClient() may trigger OnFrameInfo(). |
- done_cb.Run(entry->video_capture_controller.GetWeakPtrForIOThread()); |
- entry->video_capture_controller.AddClient(client_id, client_handler, |
- session_id, params); |
-} |
- |
-void VideoCaptureManager::StopCaptureForClient( |
- VideoCaptureController* controller, |
- VideoCaptureControllerID client_id, |
- VideoCaptureControllerEventHandler* client_handler, |
- bool aborted_due_to_error) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(controller); |
- DCHECK(client_handler); |
- |
- DeviceEntry* entry = GetDeviceEntryByController(controller); |
- if (!entry) { |
- NOTREACHED(); |
- return; |
- } |
- if (!aborted_due_to_error) { |
- if (controller->has_received_frames()) { |
- LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_OK); |
- } else if (entry->stream_type == MEDIA_DEVICE_VIDEO_CAPTURE) { |
- LogVideoCaptureEvent( |
- VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DEVICE); |
- } else { |
- LogVideoCaptureEvent( |
- VIDEO_CAPTURE_STOP_CAPTURE_OK_NO_FRAMES_PRODUCED_BY_DESKTOP_OR_TAB); |
- } |
- } else { |
- LogVideoCaptureEvent(VIDEO_CAPTURE_STOP_CAPTURE_DUE_TO_ERROR); |
- for (auto it : sessions_) { |
- if (it.second.type == entry->stream_type && it.second.id == entry->id) { |
- for (auto& listener : listeners_) |
- listener.Aborted(it.second.type, it.first); |
- // Aborted() call might synchronously destroy |entry|, recheck. |
- entry = GetDeviceEntryByController(controller); |
- if (!entry) |
- return; |
- break; |
- } |
- } |
- } |
- |
- // Detach client from controller. |
- const media::VideoCaptureSessionId session_id = |
- controller->RemoveClient(client_id, client_handler); |
- DVLOG(1) << __func__ << ", session_id = " << session_id; |
- |
- // If controller has no more clients, delete controller and device. |
- DestroyDeviceEntryIfNoClients(entry); |
-} |
- |
-void VideoCaptureManager::PauseCaptureForClient( |
- VideoCaptureController* controller, |
- VideoCaptureControllerID client_id, |
- VideoCaptureControllerEventHandler* client_handler) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(controller); |
- DCHECK(client_handler); |
- DeviceEntry* entry = GetDeviceEntryByController(controller); |
- if (!entry) |
- NOTREACHED() << "Got Null entry while pausing capture"; |
- |
- const bool had_active_client = controller->HasActiveClient(); |
- controller->PauseClient(client_id, client_handler); |
- if (!had_active_client || controller->HasActiveClient()) |
- return; |
- if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureDevice::MaybeSuspend, |
- // Unretained is safe to use here because |device| would be |
- // null if it was scheduled for shutdown and destruction, and |
- // because this task is guaranteed to run before the task |
- // that destroys the |device|. |
- base::Unretained(device))); |
- } |
-} |
- |
-void VideoCaptureManager::ResumeCaptureForClient( |
- media::VideoCaptureSessionId session_id, |
- const media::VideoCaptureParams& params, |
- VideoCaptureController* controller, |
- VideoCaptureControllerID client_id, |
- VideoCaptureControllerEventHandler* client_handler) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(controller); |
- DCHECK(client_handler); |
- |
- DeviceEntry* entry = GetDeviceEntryByController(controller); |
- if (!entry) |
- NOTREACHED() << "Got Null entry while resuming capture"; |
- |
- const bool had_active_client = controller->HasActiveClient(); |
- controller->ResumeClient(client_id, client_handler); |
- if (had_active_client || !controller->HasActiveClient()) |
- return; |
- if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureDevice::Resume, |
- // Unretained is safe to use here because |device| would be |
- // null if it was scheduled for shutdown and destruction, and |
- // because this task is guaranteed to run before the task |
- // that destroys the |device|. |
- base::Unretained(device))); |
- } |
-} |
- |
-void VideoCaptureManager::RequestRefreshFrameForClient( |
- VideoCaptureController* controller) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- if (DeviceEntry* entry = GetDeviceEntryByController(controller)) { |
- if (media::VideoCaptureDevice* device = entry->video_capture_device.get()) { |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureDevice::RequestRefreshFrame, |
- // Unretained is safe to use here because |device| would be |
- // null if it was scheduled for shutdown and destruction, |
- // and because this task is guaranteed to run before the |
- // task that destroys the |device|. |
- base::Unretained(device))); |
- } |
- } |
-} |
- |
-bool VideoCaptureManager::GetDeviceSupportedFormats( |
- media::VideoCaptureSessionId capture_session_id, |
- media::VideoCaptureFormats* supported_formats) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(supported_formats->empty()); |
- |
- SessionMap::iterator it = sessions_.find(capture_session_id); |
- if (it == sessions_.end()) |
- return false; |
- DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name; |
- |
- return GetDeviceSupportedFormats(it->second.id, supported_formats); |
-} |
- |
-bool VideoCaptureManager::GetDeviceSupportedFormats( |
- const std::string& device_id, |
- media::VideoCaptureFormats* supported_formats) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(supported_formats->empty()); |
- |
- // Return all available formats of the device, regardless its started state. |
- DeviceInfo* existing_device = GetDeviceInfoById(device_id); |
- if (existing_device) |
- *supported_formats = existing_device->supported_formats; |
- return true; |
-} |
- |
-bool VideoCaptureManager::GetDeviceFormatsInUse( |
- media::VideoCaptureSessionId capture_session_id, |
- media::VideoCaptureFormats* formats_in_use) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(formats_in_use->empty()); |
- |
- SessionMap::iterator it = sessions_.find(capture_session_id); |
- if (it == sessions_.end()) |
- return false; |
- DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name; |
- |
- return GetDeviceFormatsInUse(it->second.type, it->second.id, formats_in_use); |
-} |
- |
-bool VideoCaptureManager::GetDeviceFormatsInUse( |
- MediaStreamType stream_type, |
- const std::string& device_id, |
- media::VideoCaptureFormats* formats_in_use) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- DCHECK(formats_in_use->empty()); |
- // Return the currently in-use format(s) of the device, if it's started. |
- DeviceEntry* device_in_use = |
- GetDeviceEntryByTypeAndId(stream_type, device_id); |
- if (device_in_use) { |
- // Currently only one format-in-use is supported at the VCC level. |
- formats_in_use->push_back( |
- device_in_use->video_capture_controller.GetVideoCaptureFormat()); |
- } |
- return true; |
-} |
- |
-void VideoCaptureManager::SetDesktopCaptureWindowId( |
- media::VideoCaptureSessionId session_id, |
- gfx::NativeViewId window_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- VLOG(2) << "SetDesktopCaptureWindowId called for session " << session_id; |
- |
- notification_window_ids_[session_id] = window_id; |
- MaybePostDesktopCaptureWindowId(session_id); |
-} |
- |
-void VideoCaptureManager::MaybePostDesktopCaptureWindowId( |
- media::VideoCaptureSessionId session_id) { |
- SessionMap::iterator session_it = sessions_.find(session_id); |
- if (session_it == sessions_.end()) |
- return; |
- |
- DeviceEntry* const existing_device = |
- GetDeviceEntryByTypeAndId(session_it->second.type, session_it->second.id); |
- if (!existing_device) { |
- DVLOG(2) << "Failed to find an existing screen capture device."; |
- return; |
- } |
- |
- if (!existing_device->video_capture_device) { |
- DVLOG(2) << "Screen capture device not yet started."; |
- return; |
- } |
- |
- DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type); |
- DesktopMediaID id = DesktopMediaID::Parse(existing_device->id); |
- if (id.is_null()) |
- return; |
- |
- auto window_id_it = notification_window_ids_.find(session_id); |
- if (window_id_it == notification_window_ids_.end()) { |
- DVLOG(2) << "Notification window id not set for screen capture."; |
- return; |
- } |
- |
- // Post |existing_device->video_capture_device| to the VideoCaptureDevice to |
- // the device_task_runner_. This is safe since the device is destroyed on the |
- // device_task_runner_. |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread, |
- this, existing_device->video_capture_device.get(), |
- window_id_it->second)); |
- |
- notification_window_ids_.erase(window_id_it); |
-} |
- |
-void VideoCaptureManager::GetPhotoCapabilities( |
- int session_id, |
- VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); |
- if (!entry) |
- return; |
- VideoCaptureDevice* device = entry->video_capture_device.get(); |
- if (device) { |
- VideoCaptureManager::DoGetPhotoCapabilities(std::move(callback), device); |
- return; |
- } |
- // |entry| is known but |device| is nullptr, queue up a request for later. |
- photo_request_queue_.emplace_back( |
- session_id, base::Bind(&VideoCaptureManager::DoGetPhotoCapabilities, this, |
- base::Passed(&callback))); |
-} |
- |
-void VideoCaptureManager::SetPhotoOptions( |
- int session_id, |
- media::mojom::PhotoSettingsPtr settings, |
- VideoCaptureDevice::SetPhotoOptionsCallback callback) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); |
- if (!entry) |
- return; |
- VideoCaptureDevice* device = entry->video_capture_device.get(); |
- if (device) { |
- VideoCaptureManager::DoSetPhotoOptions(std::move(callback), |
- std::move(settings), device); |
- return; |
- } |
- // |entry| is known but |device| is nullptr, queue up a request for later. |
- photo_request_queue_.emplace_back( |
- session_id, base::Bind(&VideoCaptureManager::DoSetPhotoOptions, this, |
- base::Passed(&callback), base::Passed(&settings))); |
-} |
- |
-void VideoCaptureManager::TakePhoto( |
- int session_id, |
- VideoCaptureDevice::TakePhotoCallback callback) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- const DeviceEntry* entry = GetDeviceEntryBySessionId(session_id); |
- if (!entry) |
- return; |
- VideoCaptureDevice* device = entry->video_capture_device.get(); |
- if (device) { |
- VideoCaptureManager::DoTakePhoto(std::move(callback), device); |
- return; |
- } |
- // |entry| is known but |device| is nullptr, queue up a request for later. |
- photo_request_queue_.emplace_back( |
- session_id, base::Bind(&VideoCaptureManager::DoTakePhoto, this, |
- base::Passed(&callback))); |
-} |
- |
-void VideoCaptureManager::DoStopDeviceOnDeviceThread( |
- std::unique_ptr<VideoCaptureDevice> device) { |
- SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime"); |
- DCHECK(IsOnDeviceThread()); |
- device->StopAndDeAllocate(); |
- DVLOG(3) << "DoStopDeviceOnDeviceThread"; |
-} |
- |
-void VideoCaptureManager::OnOpened( |
- MediaStreamType stream_type, |
- media::VideoCaptureSessionId capture_session_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- for (auto& listener : listeners_) |
- listener.Opened(stream_type, capture_session_id); |
-} |
- |
-void VideoCaptureManager::OnClosed( |
- MediaStreamType stream_type, |
- media::VideoCaptureSessionId capture_session_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- for (auto& listener : listeners_) |
- listener.Closed(stream_type, capture_session_id); |
-} |
- |
-void VideoCaptureManager::OnDevicesInfoEnumerated( |
- base::ElapsedTimer* timer, |
- const EnumerationCallback& client_callback, |
- const VideoCaptureManager::DeviceInfos& new_devices_info_cache) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- UMA_HISTOGRAM_TIMES( |
- "Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime", |
- timer->Elapsed()); |
- devices_info_cache_ = new_devices_info_cache; |
- |
- // Walk the |devices_info_cache_| and produce a |
- // media::VideoCaptureDeviceDescriptors for return purposes. |
- media::VideoCaptureDeviceDescriptors devices; |
- std::vector<std::tuple<media::VideoCaptureDeviceDescriptor, |
- media::VideoCaptureFormats>> |
- descriptors_and_formats; |
- for (const auto& it : devices_info_cache_) { |
- devices.emplace_back(it.descriptor); |
- descriptors_and_formats.emplace_back(it.descriptor, it.supported_formats); |
- } |
- |
- if (!descriptors_and_formats.empty()) { |
- MediaInternals::GetInstance()->UpdateVideoCaptureDeviceCapabilities( |
- descriptors_and_formats); |
- } |
- |
- client_callback.Run(devices); |
-} |
- |
-bool VideoCaptureManager::IsOnDeviceThread() const { |
- return device_task_runner_->BelongsToCurrentThread(); |
-} |
- |
-void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread( |
- base::Callback<void(const VideoCaptureManager::DeviceInfos&)> |
- on_devices_enumerated_callback, |
- const VideoCaptureManager::DeviceInfos& old_device_info_cache, |
- std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors_snapshot) { |
- DCHECK(IsOnDeviceThread()); |
- // Construct |new_devices_info_cache| with the cached devices that are still |
- // present in the system, and remove their names from |names_snapshot|, so we |
- // keep there the truly new devices. |
- VideoCaptureManager::DeviceInfos new_devices_info_cache; |
- for (const auto& device_info : old_device_info_cache) { |
- for (VideoCaptureDeviceDescriptors::iterator it = |
- descriptors_snapshot->begin(); |
- it != descriptors_snapshot->end(); ++it) { |
- if (device_info.descriptor.device_id == it->device_id) { |
- new_devices_info_cache.push_back(device_info); |
- descriptors_snapshot->erase(it); |
- break; |
- } |
- } |
- } |
- |
- // Get the device info for the new devices in |names_snapshot|. |
- for (const auto& it : *descriptors_snapshot) { |
- DeviceInfo device_info(it); |
- video_capture_device_factory_->GetSupportedFormats( |
- it, &device_info.supported_formats); |
- ConsolidateCaptureFormats(&device_info.supported_formats); |
- new_devices_info_cache.push_back(device_info); |
- } |
- |
- on_devices_enumerated_callback.Run(new_devices_info_cache); |
-} |
- |
-void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- // Removal of the last client stops the device. |
- if (!entry->video_capture_controller.HasActiveClient() && |
- !entry->video_capture_controller.HasPausedClient()) { |
- DVLOG(1) << "VideoCaptureManager stopping device (type = " |
- << entry->stream_type << ", id = " << entry->id << ")"; |
- |
- // The DeviceEntry is removed from |devices_| immediately. The controller is |
- // deleted immediately, and the device is freed asynchronously. After this |
- // point, subsequent requests to open this same device ID will create a new |
- // DeviceEntry, VideoCaptureController, and VideoCaptureDevice. |
- DoStopDevice(entry); |
- // TODO(mcasas): use a helper function https://crbug.com/624854. |
- DeviceEntries::iterator device_it = |
- std::find_if(devices_.begin(), devices_.end(), |
- [entry](const std::unique_ptr<DeviceEntry>& device_entry) { |
- return device_entry.get() == entry; |
- }); |
- devices_.erase(device_it); |
- } |
-} |
- |
-VideoCaptureManager::DeviceEntry* |
-VideoCaptureManager::GetDeviceEntryBySessionId(int session_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- SessionMap::const_iterator session_it = sessions_.find(session_id); |
- if (session_it == sessions_.end()) |
- return nullptr; |
- |
- return GetDeviceEntryByTypeAndId(session_it->second.type, |
- session_it->second.id); |
-} |
- |
-VideoCaptureManager::DeviceEntry* |
-VideoCaptureManager::GetDeviceEntryByTypeAndId( |
- MediaStreamType type, |
- const std::string& device_id) const { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- for (const std::unique_ptr<DeviceEntry>& device : devices_) { |
- if (type == device->stream_type && device_id == device->id) |
- return device.get(); |
- } |
- return nullptr; |
-} |
- |
-VideoCaptureManager::DeviceEntry* |
-VideoCaptureManager::GetDeviceEntryByController( |
- const VideoCaptureController* controller) const { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- // Look up |controller| in |devices_|. |
- for (const std::unique_ptr<DeviceEntry>& device : devices_) { |
- if (&device->video_capture_controller == controller) |
- return device.get(); |
- } |
- return nullptr; |
-} |
- |
-VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetDeviceEntryBySerialId( |
- int serial_id) const { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- for (const std::unique_ptr<DeviceEntry>& device : devices_) { |
- if (device->serial_id == serial_id) |
- return device.get(); |
- } |
- return nullptr; |
-} |
- |
-VideoCaptureManager::DeviceInfo* VideoCaptureManager::GetDeviceInfoById( |
- const std::string& id) { |
- for (auto& it : devices_info_cache_) { |
- if (it.descriptor.device_id == id) |
- return ⁢ |
- } |
- return nullptr; |
-} |
- |
-VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry( |
- media::VideoCaptureSessionId capture_session_id, |
- const media::VideoCaptureParams& params) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- SessionMap::iterator session_it = sessions_.find(capture_session_id); |
- if (session_it == sessions_.end()) |
- return nullptr; |
- const MediaStreamDevice& device_info = session_it->second; |
- |
- // Check if another session has already opened this device. If so, just |
- // use that opened device. |
- DeviceEntry* const existing_device = |
- GetDeviceEntryByTypeAndId(device_info.type, device_info.id); |
- if (existing_device) { |
- DCHECK_EQ(device_info.type, existing_device->stream_type); |
- return existing_device; |
- } |
- |
- devices_.emplace_back( |
- new DeviceEntry(device_info.type, device_info.id, params)); |
- return devices_.back().get(); |
+ video_capture_device->AllocateAndStart(params, std::move(device_client)); |
+ result_callback.Run(std::move(video_capture_device)); |
} |
-void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread( |
- media::VideoCaptureDevice* device, |
- gfx::NativeViewId window_id) { |
- DCHECK(IsOnDeviceThread()); |
-#if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && !defined(OS_ANDROID) |
+void InProcessBuildableVideoCaptureDevice:: |
+ SetDesktopCaptureWindowIdOnDeviceThread( |
+ media::VideoCaptureDevice* device, |
+ gfx::NativeViewId window_id, |
+ std::unique_ptr<Ownership> context_reference) { |
+ DCHECK(device_task_runner_->BelongsToCurrentThread()); |
+#if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && \ |
+ !defined(OS_ANDROID) |
DesktopCaptureDevice* desktop_device = |
static_cast<DesktopCaptureDevice*>(device); |
desktop_device->SetNotificationWindowId(window_id); |
@@ -1234,104 +422,4 @@ void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread( |
#endif |
} |
-void VideoCaptureManager::DoGetPhotoCapabilities( |
- VideoCaptureDevice::GetPhotoCapabilitiesCallback callback, |
- VideoCaptureDevice* device) { |
- // Unretained() is safe to use here because |device| would be null if it |
- // was scheduled for shutdown and destruction, and because this task is |
- // guaranteed to run before the task that destroys the |device|. |
- device_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&VideoCaptureDevice::GetPhotoCapabilities, |
- base::Unretained(device), base::Passed(&callback))); |
-} |
- |
-void VideoCaptureManager::DoSetPhotoOptions( |
- VideoCaptureDevice::SetPhotoOptionsCallback callback, |
- media::mojom::PhotoSettingsPtr settings, |
- VideoCaptureDevice* device) { |
- // Unretained() is safe to use here because |device| would be null if it |
- // was scheduled for shutdown and destruction, and because this task is |
- // guaranteed to run before the task that destroys the |device|. |
- device_task_runner_->PostTask( |
- FROM_HERE, |
- base::Bind(&VideoCaptureDevice::SetPhotoOptions, base::Unretained(device), |
- base::Passed(&settings), base::Passed(&callback))); |
-} |
- |
-void VideoCaptureManager::DoTakePhoto( |
- VideoCaptureDevice::TakePhotoCallback callback, |
- VideoCaptureDevice* device) { |
- // Unretained() is safe to use here because |device| would be null if it |
- // was scheduled for shutdown and destruction, and because this task is |
- // guaranteed to run before the task that destroys the |device|. |
- device_task_runner_->PostTask( |
- FROM_HERE, base::Bind(&VideoCaptureDevice::TakePhoto, |
- base::Unretained(device), base::Passed(&callback))); |
-} |
- |
-base::Optional<CameraCalibration> VideoCaptureManager::GetCameraCalibration( |
- const std::string& device_id) { |
- VideoCaptureManager::DeviceInfo* info = GetDeviceInfoById(device_id); |
- if (!info) |
- return base::Optional<CameraCalibration>(); |
- return info->descriptor.camera_calibration; |
-} |
- |
-#if defined(OS_ANDROID) |
-void VideoCaptureManager::OnApplicationStateChange( |
- base::android::ApplicationState state) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- // Only release/resume devices when the Application state changes from |
- // RUNNING->STOPPED->RUNNING. |
- if (state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES && |
- !application_state_has_running_activities_) { |
- ResumeDevices(); |
- application_state_has_running_activities_ = true; |
- } else if (state == base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES) { |
- ReleaseDevices(); |
- application_state_has_running_activities_ = false; |
- } |
-} |
- |
-void VideoCaptureManager::ReleaseDevices() { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- for (auto& entry : devices_) { |
- // Do not stop Content Video Capture devices, e.g. Tab or Screen capture. |
- if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE) |
- continue; |
- |
- DoStopDevice(entry.get()); |
- } |
-} |
- |
-void VideoCaptureManager::ResumeDevices() { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- |
- for (auto& entry : devices_) { |
- // Do not resume Content Video Capture devices, e.g. Tab or Screen capture. |
- // Do not try to restart already running devices. |
- if (entry->stream_type != MEDIA_DEVICE_VIDEO_CAPTURE || |
- entry->video_capture_device) |
- continue; |
- |
- // Check if the device is already in the start queue. |
- bool device_in_queue = false; |
- for (auto& request : device_start_queue_) { |
- if (request.serial_id() == entry->serial_id) { |
- device_in_queue = true; |
- break; |
- } |
- } |
- |
- if (!device_in_queue) { |
- // Session ID is only valid for Screen capture. So we can fake it to |
- // resume video capture devices here. |
- QueueStartDevice(kFakeSessionId, entry.get(), entry->parameters); |
- } |
- } |
-} |
-#endif // defined(OS_ANDROID) |
- |
} // namespace content |