Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / media / video_capture_manager.cc
index 28242f4..6568407 100644 (file)
@@ -7,32 +7,69 @@
 #include <set>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
 #include "base/task_runner_util.h"
 #include "base/threading/sequenced_worker_pool.h"
+#include "content/browser/media/capture/web_contents_video_capture_device.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/web_contents_video_capture_device.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/media_stream_request.h"
-#include "media/base/media_switches.h"
 #include "media/base/scoped_histogram_timer.h"
-#include "media/video/capture/fake_video_capture_device.h"
-#include "media/video/capture/file_video_capture_device.h"
 #include "media/video/capture/video_capture_device.h"
+#include "media/video/capture/video_capture_device_factory.h"
 
 #if defined(ENABLE_SCREEN_CAPTURE)
-#include "content/browser/renderer_host/media/desktop_capture_device.h"
+#include "content/browser/media/capture/desktop_capture_device.h"
 #if defined(USE_AURA)
-#include "content/browser/renderer_host/media/desktop_capture_device_aura.h"
+#include "content/browser/media/capture/desktop_capture_device_aura.h"
 #endif
 #endif
 
+namespace {
+
+// 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) {
+  if (format1.frame_size.GetArea() == format2.frame_size.GetArea())
+    return format1.frame_rate > format2.frame_rate;
+  return format1.frame_size.GetArea() < format2.frame_size.GetArea();
+}
+
+bool IsCaptureFormatSizeEqual(const media::VideoCaptureFormat& format1,
+                              const media::VideoCaptureFormat& format2) {
+  return format1.frame_size.GetArea() == format2.frame_size.GetArea();
+}
+
+// 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.
+  for (media::VideoCaptureFormats::iterator it = formats->begin();
+       it != formats->end(); ++it) {
+    it->pixel_format = media::PIXEL_FORMAT_I420;
+  }
+}
+
+}  // namespace
+
 namespace content {
 
 VideoCaptureManager::DeviceEntry::DeviceEntry(
@@ -55,23 +92,25 @@ VideoCaptureManager::DeviceInfo::DeviceInfo(
 
 VideoCaptureManager::DeviceInfo::~DeviceInfo() {}
 
-VideoCaptureManager::VideoCaptureManager()
+VideoCaptureManager::VideoCaptureManager(
+    scoped_ptr<media::VideoCaptureDeviceFactory> factory)
     : listener_(NULL),
       new_capture_session_id_(1),
-      artificial_device_source_for_testing_(DISABLED) {
+      video_capture_device_factory_(factory.Pass()) {
 }
 
 VideoCaptureManager::~VideoCaptureManager() {
   DCHECK(devices_.empty());
 }
 
-void VideoCaptureManager::Register(MediaStreamProviderListener* listener,
-                                   base::MessageLoopProxy* device_thread_loop) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+void VideoCaptureManager::Register(
+    MediaStreamProviderListener* listener,
+    const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(!listener_);
-  DCHECK(!device_loop_.get());
+  DCHECK(!device_task_runner_.get());
   listener_ = listener;
-  device_loop_ = device_thread_loop;
+  device_task_runner_ = device_task_runner;
 }
 
 void VideoCaptureManager::Unregister() {
@@ -80,11 +119,11 @@ void VideoCaptureManager::Unregister() {
 }
 
 void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
   DCHECK(listener_);
   base::PostTaskAndReplyWithResult(
-      device_loop_, FROM_HERE,
+      device_task_runner_, FROM_HERE,
       base::Bind(&VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread,
                  this, stream_type, devices_info_cache_),
       base::Bind(&VideoCaptureManager::OnDevicesInfoEnumerated, this,
@@ -92,7 +131,7 @@ void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
 }
 
 int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(listener_);
 
   // Generate a new id for the session being opened.
@@ -115,12 +154,11 @@ int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
 }
 
 void VideoCaptureManager::Close(int capture_session_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(listener_);
   DVLOG(1) << "VideoCaptureManager::Close, id " << capture_session_id;
 
-  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator
-      session_it = sessions_.find(capture_session_id);
+  SessionMap::iterator session_it = sessions_.find(capture_session_id);
   if (session_it == sessions_.end()) {
     NOTREACHED();
     return;
@@ -145,16 +183,8 @@ void VideoCaptureManager::Close(int capture_session_id) {
   sessions_.erase(session_it);
 }
 
-void VideoCaptureManager::UseFakeDevice() {
-  if (CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kUseFileForFakeVideoCapture)) {
-    artificial_device_source_for_testing_ = Y4M_FILE;
-  } else {
-    artificial_device_source_for_testing_ = TEST_PATTERN;
-  }
-}
-
 void VideoCaptureManager::DoStartDeviceOnDeviceThread(
+    media::VideoCaptureSessionId session_id,
     DeviceEntry* entry,
     const media::VideoCaptureParams& params,
     scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
@@ -169,20 +199,8 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
       // held in the browser-side VideoCaptureDevice::Name structure.
       DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
       if (found) {
-        switch (artificial_device_source_for_testing_) {
-          case DISABLED:
-            video_capture_device.reset(
-                media::VideoCaptureDevice::Create(found->name));
-            break;
-          case TEST_PATTERN:
-            video_capture_device.reset(
-                media::FakeVideoCaptureDevice::Create(found->name));
-            break;
-          case Y4M_FILE:
-            video_capture_device.reset(
-                media::FileVideoCaptureDevice::Create(found->name));
-            break;
-        }
+        video_capture_device =
+            video_capture_device_factory_->Create(found->name);
       }
       break;
     }
@@ -202,6 +220,11 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
       if (id.type != DesktopMediaID::TYPE_NONE &&
           id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
         video_capture_device = DesktopCaptureDevice::Create(id);
+        if (notification_window_ids_.find(session_id) !=
+            notification_window_ids_.end()) {
+          static_cast<DesktopCaptureDevice*>(video_capture_device.get())
+              ->SetNotificationWindowId(notification_window_ids_[session_id]);
+        }
       }
 #endif  // defined(ENABLE_SCREEN_CAPTURE)
       break;
@@ -228,7 +251,7 @@ void VideoCaptureManager::StartCaptureForClient(
     VideoCaptureControllerID client_id,
     VideoCaptureControllerEventHandler* client_handler,
     const DoneCB& done_cb) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DVLOG(1) << "VideoCaptureManager::StartCaptureForClient, "
            << params.requested_format.frame_size.ToString() << ", "
            << params.requested_format.frame_rate << ", #" << session_id << ")";
@@ -246,11 +269,12 @@ void VideoCaptureManager::StartCaptureForClient(
     DVLOG(1) << "VideoCaptureManager starting device (type = "
              << entry->stream_type << ", id = " << entry->id << ")";
 
-    device_loop_->PostTask(
+    device_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(
             &VideoCaptureManager::DoStartDeviceOnDeviceThread,
             this,
+            session_id,
             entry,
             params,
             base::Passed(entry->video_capture_controller->NewDeviceClient())));
@@ -264,8 +288,9 @@ void VideoCaptureManager::StartCaptureForClient(
 void VideoCaptureManager::StopCaptureForClient(
     VideoCaptureController* controller,
     VideoCaptureControllerID client_id,
-    VideoCaptureControllerEventHandler* client_handler) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+    VideoCaptureControllerEventHandler* client_handler,
+    bool aborted_due_to_error) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(controller);
   DCHECK(client_handler);
 
@@ -274,6 +299,16 @@ void VideoCaptureManager::StopCaptureForClient(
     NOTREACHED();
     return;
   }
+  if (aborted_due_to_error) {
+    SessionMap::iterator it;
+    for (it = sessions_.begin(); it != sessions_.end(); ++it) {
+      if (it->second.type == entry->stream_type &&
+          it->second.id == entry->id) {
+        listener_->Aborted(it->second.type, it->first);
+        break;
+      }
+    }
+  }
 
   // Detach client from controller.
   media::VideoCaptureSessionId session_id =
@@ -288,11 +323,10 @@ void VideoCaptureManager::StopCaptureForClient(
 bool VideoCaptureManager::GetDeviceSupportedFormats(
     media::VideoCaptureSessionId capture_session_id,
     media::VideoCaptureFormats* supported_formats) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(supported_formats->empty());
 
-  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator it =
-      sessions_.find(capture_session_id);
+  SessionMap::iterator it = sessions_.find(capture_session_id);
   if (it == sessions_.end())
     return false;
   DVLOG(1) << "GetDeviceSupportedFormats for device: " << it->second.name;
@@ -305,27 +339,64 @@ bool VideoCaptureManager::GetDeviceSupportedFormats(
   return true;
 }
 
-bool VideoCaptureManager::GetDeviceFormatInUse(
+bool VideoCaptureManager::GetDeviceFormatsInUse(
     media::VideoCaptureSessionId capture_session_id,
-    media::VideoCaptureFormat* format_in_use) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+    media::VideoCaptureFormats* formats_in_use) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK(formats_in_use->empty());
 
-  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator it =
-      sessions_.find(capture_session_id);
+  SessionMap::iterator it = sessions_.find(capture_session_id);
   if (it == sessions_.end())
     return false;
-  DVLOG(1) << "GetDeviceFormatInUse for device: " << it->second.name;
+  DVLOG(1) << "GetDeviceFormatsInUse for device: " << it->second.name;
 
-  // Return the currently in-use format of the device, if it's started.
+  // Return the currently in-use format(s) of the device, if it's started.
   DeviceEntry* device_in_use =
       GetDeviceEntryForMediaStreamDevice(it->second);
-  if (!device_in_use)
-    return false;
-  *format_in_use =
-      device_in_use->video_capture_controller->GetVideoCaptureFormat();
+  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);
+  SessionMap::iterator session_it = sessions_.find(session_id);
+  if (session_it == sessions_.end()) {
+    device_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(
+            &VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread,
+            this,
+            session_id,
+            window_id));
+    return;
+  }
+
+  DeviceEntry* const existing_device =
+      GetDeviceEntryForMediaStreamDevice(session_it->second);
+  if (!existing_device)
+    return;
+
+  DCHECK_EQ(MEDIA_DESKTOP_VIDEO_CAPTURE, existing_device->stream_type);
+  DesktopMediaID id = DesktopMediaID::Parse(existing_device->id);
+  if (id.type == DesktopMediaID::TYPE_NONE ||
+      id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
+    return;
+  }
+
+  device_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
+                 this,
+                 existing_device,
+                 window_id));
+}
+
 void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
   SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
   DCHECK(IsOnDeviceThread());
@@ -338,7 +409,7 @@ void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
 void VideoCaptureManager::OnOpened(
     MediaStreamType stream_type,
     media::VideoCaptureSessionId capture_session_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!listener_) {
     // Listener has been removed.
     return;
@@ -349,7 +420,7 @@ void VideoCaptureManager::OnOpened(
 void VideoCaptureManager::OnClosed(
     MediaStreamType stream_type,
     media::VideoCaptureSessionId capture_session_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!listener_) {
     // Listener has been removed.
     return;
@@ -360,7 +431,7 @@ void VideoCaptureManager::OnClosed(
 void VideoCaptureManager::OnDevicesInfoEnumerated(
     MediaStreamType stream_type,
     const DeviceInfos& new_devices_info_cache) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   if (!listener_) {
     // Listener has been removed.
@@ -380,7 +451,7 @@ void VideoCaptureManager::OnDevicesInfoEnumerated(
 }
 
 bool VideoCaptureManager::IsOnDeviceThread() const {
-  return device_loop_->BelongsToCurrentThread();
+  return device_task_runner_->BelongsToCurrentThread();
 }
 
 VideoCaptureManager::DeviceInfos
@@ -396,23 +467,11 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
       // Cache the latest enumeration of video capture devices.
       // We'll refer to this list again in OnOpen to avoid having to
       // enumerate the devices again.
-      switch (artificial_device_source_for_testing_) {
-        case DISABLED:
-          media::VideoCaptureDevice::GetDeviceNames(&names_snapshot);
-          break;
-        case TEST_PATTERN:
-          media::FakeVideoCaptureDevice::GetDeviceNames(&names_snapshot);
-          break;
-        case Y4M_FILE:
-          media::FileVideoCaptureDevice::GetDeviceNames(&names_snapshot);
-          break;
-      }
+      video_capture_device_factory_->GetDeviceNames(&names_snapshot);
       break;
-
     case MEDIA_DESKTOP_VIDEO_CAPTURE:
       // Do nothing.
       break;
-
     default:
       NOTREACHED();
       break;
@@ -442,20 +501,9 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
        it != names_snapshot.end(); ++it) {
     media::VideoCaptureFormats supported_formats;
     DeviceInfo device_info(*it, media::VideoCaptureFormats());
-    switch (artificial_device_source_for_testing_) {
-      case DISABLED:
-        media::VideoCaptureDevice::GetDeviceSupportedFormats(
-            *it, &(device_info.supported_formats));
-        break;
-      case TEST_PATTERN:
-        media::FakeVideoCaptureDevice::GetDeviceSupportedFormats(
-            *it, &(device_info.supported_formats));
-        break;
-      case Y4M_FILE:
-        media::FileVideoCaptureDevice::GetDeviceSupportedFormats(
-            *it, &(device_info.supported_formats));
-        break;
-    }
+    video_capture_device_factory_->GetDeviceSupportedFormats(
+        *it, &(device_info.supported_formats));
+    ConsolidateCaptureFormats(&device_info.supported_formats);
     new_devices_info_cache.push_back(device_info);
   }
   return new_devices_info_cache;
@@ -464,7 +512,7 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
 VideoCaptureManager::DeviceEntry*
 VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
     const MediaStreamDevice& device_info) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   for (DeviceEntries::iterator it = devices_.begin();
        it != devices_.end(); ++it) {
@@ -479,9 +527,9 @@ VideoCaptureManager::GetDeviceEntryForMediaStreamDevice(
 
 VideoCaptureManager::DeviceEntry*
 VideoCaptureManager::GetDeviceEntryForController(
-    const VideoCaptureController* controller) {
+    const VideoCaptureController* controller) const {
   // Look up |controller| in |devices_|.
-  for (DeviceEntries::iterator it = devices_.begin();
+  for (DeviceEntries::const_iterator it = devices_.begin();
        it != devices_.end(); ++it) {
     if ((*it)->video_capture_controller.get() == controller) {
       return *it;
@@ -491,7 +539,7 @@ VideoCaptureManager::GetDeviceEntryForController(
 }
 
 void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Removal of the last client stops the device.
   if (entry->video_capture_controller->GetClientCount() == 0) {
     DVLOG(1) << "VideoCaptureManager stopping device (type = "
@@ -503,7 +551,7 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
     // DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
     devices_.erase(entry);
     entry->video_capture_controller.reset();
-    device_loop_->PostTask(
+    device_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
                    base::Owned(entry)));
@@ -512,10 +560,9 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
 
 VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
     media::VideoCaptureSessionId capture_session_id) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  std::map<media::VideoCaptureSessionId, MediaStreamDevice>::iterator
-      session_it = sessions_.find(capture_session_id);
+  SessionMap::iterator session_it = sessions_.find(capture_session_id);
   if (session_it == sessions_.end()) {
     return NULL;
   }
@@ -550,4 +597,25 @@ VideoCaptureManager::DeviceInfo* VideoCaptureManager::FindDeviceInfoById(
   return NULL;
 }
 
+void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
+    DeviceEntry* entry,
+    gfx::NativeViewId window_id) {
+  DCHECK(IsOnDeviceThread());
+  DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
+#if defined(ENABLE_SCREEN_CAPTURE)
+  DesktopCaptureDevice* device =
+      static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
+  device->SetNotificationWindowId(window_id);
+#endif
+}
+
+void VideoCaptureManager::SaveDesktopCaptureWindowIdOnDeviceThread(
+    media::VideoCaptureSessionId session_id,
+    gfx::NativeViewId window_id) {
+  DCHECK(IsOnDeviceThread());
+  DCHECK(notification_window_ids_.find(session_id) ==
+         notification_window_ids_.end());
+  notification_window_ids_[session_id] = window_id;
+}
+
 }  // namespace content