diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 10:50:28 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 10:50:28 +0000 |
commit | 348c18bc2b9bdd6887e49f26df551b792d4e7a57 (patch) | |
tree | 9189e37024ab6225aec8c9a43cb92a4140725587 | |
parent | d20b2bc5176090837b4cad0e6344eb43ae7075e7 (diff) | |
download | chromium_src-348c18bc2b9bdd6887e49f26df551b792d4e7a57.zip chromium_src-348c18bc2b9bdd6887e49f26df551b792d4e7a57.tar.gz chromium_src-348c18bc2b9bdd6887e49f26df551b792d4e7a57.tar.bz2 |
Revert 170912 - need more delayloads.
> Video capture implementation using the Media Foundation API.
> This replaces the DirectShow based implementation for Vista,Win7 and Win8.
> DirectShow isn't supported in metro mode so once we've landed this,
> we can revert the workaround we have in place for Win8.
>
> The CapabilityList class is mostly moved code from the DS implementation.
> The difference is that I'm not using a std::map<> since that wasn't
> really necessary and instead adding one member (via inheritance) to
> the capability struct on Windows that holds the stream id that is needed.
>
> BUG=140545
> TEST=All video capture tests in media_unittests now test this new implementation (except on XP).
>
> Review URL: https://codereview.chromium.org/11419200
TBR=tommi@chromium.org
Review URL: https://codereview.chromium.org/11418307
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170925 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome_dll.gypi | 3 | ||||
-rw-r--r-- | media/media.gyp | 21 | ||||
-rw-r--r-- | media/video/capture/win/capability_list_win.cc | 114 | ||||
-rw-r--r-- | media/video/capture/win/capability_list_win.h | 50 | ||||
-rw-r--r-- | media/video/capture/win/video_capture_device_mf_win.cc | 399 | ||||
-rw-r--r-- | media/video/capture/win/video_capture_device_mf_win.h | 72 | ||||
-rw-r--r-- | media/video/capture/win/video_capture_device_win.cc | 153 | ||||
-rw-r--r-- | media/video/capture/win/video_capture_device_win.h | 7 |
8 files changed, 115 insertions, 704 deletions
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index 55408c6..169ac1e 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi @@ -183,9 +183,6 @@ 'imagehlp.dll', 'imm32.dll', 'iphlpapi.dll', - 'mf.dll', - 'mfplat.dll', - 'mfreadwrite.dll', 'setupapi.dll', 'urlmon.dll', 'winhttp.dll', diff --git a/media/media.gyp b/media/media.gyp index 595af78..ef7591b 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -314,8 +314,6 @@ 'video/capture/video_capture_proxy.cc', 'video/capture/video_capture_proxy.h', 'video/capture/video_capture_types.h', - 'video/capture/win/capability_list_win.cc', - 'video/capture/win/capability_list_win.h', 'video/capture/win/filter_base_win.cc', 'video/capture/win/filter_base_win.h', 'video/capture/win/pin_base_win.cc', @@ -325,8 +323,6 @@ 'video/capture/win/sink_filter_win.h', 'video/capture/win/sink_input_pin_win.cc', 'video/capture/win/sink_input_pin_win.h', - 'video/capture/win/video_capture_device_mf_win.cc', - 'video/capture/win/video_capture_device_mf_win.h', 'video/capture/win/video_capture_device_win.cc', 'video/capture/win/video_capture_device_win.h', 'video/picture.cc', @@ -560,23 +556,6 @@ 'video/capture/video_capture_device_dummy.cc', 'video/capture/video_capture_device_dummy.h', ], - 'link_settings': { - 'libraries': [ - '-lmf.lib', - '-lmfplat.lib', - '-lmfreadwrite.lib', - '-lmfuuid.lib', - ], - }, - 'msvs_settings': { - 'VCLinkerTool': { - 'DelayLoadDLLs': [ - 'mf.dll', - 'mfplat.dll', - 'mfreadwrite.dll', - ], - }, - }, }], ['proprietary_codecs==1 or branding=="Chrome"', { 'sources': [ diff --git a/media/video/capture/win/capability_list_win.cc b/media/video/capture/win/capability_list_win.cc deleted file mode 100644 index 63bd69b..0000000 --- a/media/video/capture/win/capability_list_win.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/video/capture/win/capability_list_win.h" - -#include <algorithm> - -#include "base/logging.h" - -namespace media { -namespace { - -// Help structure used for comparing video capture capabilities. -struct ResolutionDiff { - const VideoCaptureCapabilityWin* capability; - int diff_height; - int diff_width; - int diff_frame_rate; -}; - -bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) { - return abs(item1.diff_height) < abs(item2.diff_height); -} - -bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { - return abs(item1.diff_width) < abs(item2.diff_width); -} - -bool CompareFrameRate(const ResolutionDiff& item1, - const ResolutionDiff& item2) { - return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate); -} - -bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) { - return item1.capability->color < item2.capability->color; -} - -} // namespace. - -CapabilityList::CapabilityList() { - DetachFromThread(); -} - -CapabilityList::~CapabilityList() {} - -// Appends an entry to the list. -void CapabilityList::Add(const VideoCaptureCapabilityWin& capability) { - DCHECK(CalledOnValidThread()); - capabilities_.push_back(capability); -} - -const VideoCaptureCapabilityWin& CapabilityList::GetBestMatchedCapability( - int requested_width, - int requested_height, - int requested_frame_rate) const { - DCHECK(CalledOnValidThread()); - DCHECK(!capabilities_.empty()); - - std::list<ResolutionDiff> diff_list; - - // Loop through the candidates to create a list of differentials between the - // requested resolution and the camera capability. - for (Capabilities::const_iterator it = capabilities_.begin(); - it != capabilities_.end(); ++it) { - ResolutionDiff diff; - diff.capability = &(*it); - diff.diff_width = it->width - requested_width; - diff.diff_height = it->height - requested_height; - diff.diff_frame_rate = it->frame_rate - requested_frame_rate; - diff_list.push_back(diff); - } - - // Sort the best height candidates. - diff_list.sort(&CompareHeight); - int best_diff = diff_list.front().diff_height; - for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); - it != diff_list.end(); ++it) { - if (it->diff_height != best_diff) { - // Remove all candidates but the best. - diff_list.erase(it, diff_list.end()); - break; - } - } - - // Sort the best width candidates. - diff_list.sort(&CompareWidth); - best_diff = diff_list.front().diff_width; - for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); - it != diff_list.end(); ++it) { - if (it->diff_width != best_diff) { - // Remove all candidates but the best. - diff_list.erase(it, diff_list.end()); - break; - } - } - - // Sort the best frame rate candidates. - diff_list.sort(&CompareFrameRate); - best_diff = diff_list.front().diff_frame_rate; - for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); - it != diff_list.end(); ++it) { - if (it->diff_frame_rate != best_diff) { - diff_list.erase(it, diff_list.end()); - break; - } - } - - // Decide the best color format. - diff_list.sort(&CompareColor); - return *diff_list.front().capability; -} - -} // namespace media diff --git a/media/video/capture/win/capability_list_win.h b/media/video/capture/win/capability_list_win.h deleted file mode 100644 index 6f96942..0000000 --- a/media/video/capture/win/capability_list_win.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Windows specific implementation of VideoCaptureDevice. -// DirectShow is used for capturing. DirectShow provide its own threads -// for capturing. - -#ifndef MEDIA_VIDEO_CAPTURE_WIN_CAPABILITY_LIST_WIN_H_ -#define MEDIA_VIDEO_CAPTURE_WIN_CAPABILITY_LIST_WIN_H_ - -#include <list> - -#include "base/threading/non_thread_safe.h" -#include "media/video/capture/video_capture_types.h" - -namespace media { - -struct VideoCaptureCapabilityWin : public VideoCaptureCapability { - explicit VideoCaptureCapabilityWin(int index) : stream_index(index) {} - int stream_index; -}; - -class CapabilityList : public base::NonThreadSafe { - public: - CapabilityList(); - ~CapabilityList(); - - bool empty() const { return capabilities_.empty(); } - - // Appends an entry to the list. - void Add(const VideoCaptureCapabilityWin& capability); - - // Loops through the list of capabilities and returns an index of the best - // matching capability. The algorithm prioritizes height, width, frame rate - // and color format in that order. - const VideoCaptureCapabilityWin& GetBestMatchedCapability( - int requested_width, int requested_height, - int requested_frame_rate) const; - - private: - typedef std::list<VideoCaptureCapabilityWin> Capabilities; - Capabilities capabilities_; - - DISALLOW_COPY_AND_ASSIGN(CapabilityList); -}; - -} // namespace media - -#endif // MEDIA_VIDEO_CAPTURE_WIN_CAPABILITY_LIST_WIN_H_ diff --git a/media/video/capture/win/video_capture_device_mf_win.cc b/media/video/capture/win/video_capture_device_mf_win.cc deleted file mode 100644 index 131bc7e..0000000 --- a/media/video/capture/win/video_capture_device_mf_win.cc +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/video/capture/win/video_capture_device_mf_win.h" - -#include <mfapi.h> -#include <mferror.h> - -#include "base/lazy_instance.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/waitable_event.h" -#include "base/sys_string_conversions.h" -#include "base/win/scoped_co_mem.h" -#include "media/video/capture/win/capability_list_win.h" - -using base::win::ScopedCoMem; -using base::win::ScopedComPtr; - -namespace media { -namespace { - -class MFInitializerSingleton { - public: - MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); } - ~MFInitializerSingleton() { MFShutdown(); } -}; - -static base::LazyInstance<MFInitializerSingleton> g_mf_initialize = - LAZY_INSTANCE_INITIALIZER; - -void EnsureMFInit() { - g_mf_initialize.Get(); -} - -bool PrepareVideoCaptureAttributes(IMFAttributes** attributes, int count) { - EnsureMFInit(); - - if (FAILED(MFCreateAttributes(attributes, count))) - return false; - - return SUCCEEDED((*attributes)->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); -} - -bool EnumerateVideoDevices(IMFActivate*** devices, - UINT32* count) { - ScopedComPtr<IMFAttributes> attributes; - if (!PrepareVideoCaptureAttributes(attributes.Receive(), 1)) - return false; - - return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count)); -} - -bool CreateVideoCaptureDevice(const char* sym_link, IMFMediaSource** source) { - ScopedComPtr<IMFAttributes> attributes; - if (!PrepareVideoCaptureAttributes(attributes.Receive(), 2)) - return false; - - attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, - base::SysUTF8ToWide(sym_link).c_str()); - - return SUCCEEDED(MFCreateDeviceSource(attributes, source)); -} - -bool FormatFromGuid(const GUID& guid, VideoCaptureCapability::Format* format) { - struct { - const GUID& guid; - const VideoCaptureCapability::Format format; - } static const kFormatMap[] = { - { MFVideoFormat_I420, VideoCaptureCapability::kI420 }, - { MFVideoFormat_YUY2, VideoCaptureCapability::kYUY2 }, - { MFVideoFormat_UYVY, VideoCaptureCapability::kUYVY }, - { MFVideoFormat_RGB24, VideoCaptureCapability::kRGB24 }, - { MFVideoFormat_ARGB32, VideoCaptureCapability::kARGB }, - { MFVideoFormat_MJPG, VideoCaptureCapability::kMJPEG }, - { MFVideoFormat_YV12, VideoCaptureCapability::kYV12 }, - }; - - for (int i = 0; i < arraysize(kFormatMap); ++i) { - if (kFormatMap[i].guid == guid) { - *format = kFormatMap[i].format; - return true; - } - } - - return false; -} - -bool GetFrameSize(IMFMediaType* type, int* width, int* height) { - UINT32 width32, height32; - if (FAILED(MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width32, &height32))) - return false; - *width = width32; - *height = height32; - return true; -} - -bool GetFrameRate(IMFMediaType* type, int* frame_rate) { - UINT32 numerator, denominator; - if (FAILED(MFGetAttributeRatio(type, MF_MT_FRAME_RATE, &numerator, - &denominator))) { - return false; - } - - *frame_rate = denominator ? numerator / denominator : 0; - - return true; -} - -bool FillCapabilitiesFromType(IMFMediaType* type, - VideoCaptureCapability* capability) { - GUID type_guid; - if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &type_guid)) || - !FormatFromGuid(type_guid, &capability->color) || - !GetFrameSize(type, &capability->width, &capability->height) || - !GetFrameRate(type, &capability->frame_rate)) { - return false; - } - - capability->expected_capture_delay = 0; // Currently not used. - capability->interlaced = false; // Currently not used. - - return true; -} - -HRESULT FillCapabilities(IMFSourceReader* source, - CapabilityList* capabilities) { - DWORD stream_index = 0; - ScopedComPtr<IMFMediaType> type; - HRESULT hr; - while (SUCCEEDED(hr = source->GetNativeMediaType( - MF_SOURCE_READER_FIRST_VIDEO_STREAM, stream_index, type.Receive()))) { - VideoCaptureCapabilityWin capability(stream_index++); - if (FillCapabilitiesFromType(type, &capability)) - capabilities->Add(capability); - type.Release(); - } - - if (SUCCEEDED(hr) && capabilities->empty()) - hr = HRESULT_FROM_WIN32(ERROR_EMPTY); - - return (hr == MF_E_NO_MORE_TYPES) ? S_OK : hr; -} - -} // namespace - -class MFReaderCallback - : public base::RefCountedThreadSafe<MFReaderCallback>, - public IMFSourceReaderCallback { - public: - MFReaderCallback(VideoCaptureDeviceMFWin* observer) - : observer_(observer), wait_event_(NULL) { - } - - void SetSignalOnFlush(base::WaitableEvent* event) { - wait_event_ = event; - } - - STDMETHOD(QueryInterface)(REFIID riid, void** object) { - if (riid != IID_IUnknown && riid != IID_IMFSourceReaderCallback) - return E_NOINTERFACE; - *object = static_cast<IMFSourceReaderCallback*>(this); - AddRef(); - return S_OK; - } - - STDMETHOD_(ULONG, AddRef)() { - base::RefCountedThreadSafe<MFReaderCallback>::AddRef(); - return 1U; - } - - STDMETHOD_(ULONG, Release)() { - base::RefCountedThreadSafe<MFReaderCallback>::Release(); - return 1U; - } - - STDMETHOD(OnReadSample)(HRESULT status, DWORD stream_index, - DWORD stream_flags, LONGLONG time_stamp, IMFSample* sample) { - base::Time stamp(base::Time::Now()); - if (!sample) { - observer_->OnIncomingCapturedFrame(NULL, 0, stamp); - return S_OK; - } - - DWORD count = 0; - sample->GetBufferCount(&count); - - for (DWORD i = 0; i < count; ++i) { - ScopedComPtr<IMFMediaBuffer> buffer; - sample->GetBufferByIndex(i, buffer.Receive()); - if (buffer) { - DWORD length = 0, max_length = 0; - BYTE* data = NULL; - buffer->Lock(&data, &max_length, &length); - observer_->OnIncomingCapturedFrame(data, length, stamp); - buffer->Unlock(); - } - } - return S_OK; - } - - STDMETHOD(OnFlush)(DWORD stream_index) { - if (wait_event_) { - wait_event_->Signal(); - wait_event_ = NULL; - } - return S_OK; - } - - STDMETHOD(OnEvent)(DWORD stream_index, IMFMediaEvent* event) { - NOTIMPLEMENTED(); - return S_OK; - } - - private: - friend class base::RefCountedThreadSafe<MFReaderCallback>; - ~MFReaderCallback() {} - - VideoCaptureDeviceMFWin* observer_; - base::WaitableEvent* wait_event_; -}; - -// static -void VideoCaptureDeviceMFWin::GetDeviceNames(Names* device_names) { - ScopedCoMem<IMFActivate*> devices; - UINT32 count; - if (!EnumerateVideoDevices(&devices, &count)) - return; - - HRESULT hr; - for (UINT32 i = 0; i < count; ++i) { - UINT32 name_size, id_size; - ScopedCoMem<wchar_t> name, id; - if (SUCCEEDED(hr = devices[i]->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size)) && - SUCCEEDED(hr = devices[i]->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id, - &id_size))) { - std::wstring name_w(name, name_size), id_w(id, id_size); - Name device; - device.device_name = base::SysWideToUTF8(name_w); - device.unique_id = base::SysWideToUTF8(id_w); - device_names->push_back(device); - } else { - DLOG(WARNING) << "GetAllocatedString failed: " << std::hex << hr; - } - devices[i]->Release(); - } -} - -VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(const Name& device_name) - : name_(device_name), observer_(NULL), capture_(0) { - DetachFromThread(); -} - -VideoCaptureDeviceMFWin::~VideoCaptureDeviceMFWin() { - DCHECK(CalledOnValidThread()); -} - -bool VideoCaptureDeviceMFWin::Init() { - DCHECK(CalledOnValidThread()); - DCHECK(!reader_); - - ScopedComPtr<IMFMediaSource> source; - if (!CreateVideoCaptureDevice(name_.unique_id.c_str(), source.Receive())) - return false; - - ScopedComPtr<IMFAttributes> attributes; - MFCreateAttributes(attributes.Receive(), 1); - DCHECK(attributes); - - callback_ = new MFReaderCallback(this); - attributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, callback_.get()); - - return SUCCEEDED(MFCreateSourceReaderFromMediaSource(source, attributes, - reader_.Receive())); -} - -void VideoCaptureDeviceMFWin::Allocate( - int width, - int height, - int frame_rate, - VideoCaptureDevice::EventHandler* observer) { - DCHECK(CalledOnValidThread()); - - base::AutoLock lock(lock_); - - if (observer_) { - DCHECK_EQ(observer, observer_); - return; - } - - observer_ = observer; - DCHECK_EQ(capture_, false); - - CapabilityList capabilities; - HRESULT hr = S_OK; - if (!reader_ || FAILED(hr = FillCapabilities(reader_, &capabilities))) { - OnError(hr); - return; - } - - const VideoCaptureCapabilityWin& found_capability = - capabilities.GetBestMatchedCapability(width, height, frame_rate); - - ScopedComPtr<IMFMediaType> type; - if (FAILED(hr = reader_->GetNativeMediaType( - MF_SOURCE_READER_FIRST_VIDEO_STREAM, found_capability.stream_index, - type.Receive())) || - FAILED(hr = reader_->SetCurrentMediaType( - MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, type))) { - OnError(hr); - return; - } - - observer_->OnFrameInfo(found_capability); -} - -void VideoCaptureDeviceMFWin::Start() { - DCHECK(CalledOnValidThread()); - - base::AutoLock lock(lock_); - if (!capture_) { - capture_ = true; - HRESULT hr; - if (FAILED(hr = reader_->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, - NULL, NULL, NULL, NULL))) { - OnError(hr); - capture_ = false; - } - } -} - -void VideoCaptureDeviceMFWin::Stop() { - DCHECK(CalledOnValidThread()); - base::WaitableEvent flushed(false, false); - bool wait = false; - { - base::AutoLock lock(lock_); - if (capture_) { - capture_ = false; - callback_->SetSignalOnFlush(&flushed); - HRESULT hr = reader_->Flush(MF_SOURCE_READER_ALL_STREAMS); - wait = SUCCEEDED(hr); - if (!wait) { - callback_->SetSignalOnFlush(NULL); - OnError(hr); - } - } - } - - if (wait) - flushed.Wait(); -} - -void VideoCaptureDeviceMFWin::DeAllocate() { - DCHECK(CalledOnValidThread()); - - Stop(); - - base::AutoLock lock(lock_); - observer_ = NULL; -} - -const VideoCaptureDevice::Name& VideoCaptureDeviceMFWin::device_name() { - DCHECK(CalledOnValidThread()); - return name_; -} - -void VideoCaptureDeviceMFWin::OnIncomingCapturedFrame( - const uint8* data, - int length, - const base::Time& time_stamp) { - base::AutoLock lock(lock_); - if (data && observer_) - observer_->OnIncomingCapturedFrame(data, length, time_stamp); - - if (capture_) { - HRESULT hr = reader_->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, - NULL, NULL, NULL, NULL); - if (FAILED(hr)) { - // If running the *VideoCap* unit tests on repeat, this can sometimes - // fail with HRESULT_FROM_WINHRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION). - // It's not clear to me why this is, but it is possible that it has - // something to do with this bug: - // http://support.microsoft.com/kb/979567 - OnError(hr); - } - } -} - -void VideoCaptureDeviceMFWin::OnError(HRESULT hr) { - DLOG(ERROR) << "VideoCaptureDeviceMFWin: " << std::hex << hr; - if (observer_) - observer_->OnError(); -} - -} // namespace media diff --git a/media/video/capture/win/video_capture_device_mf_win.h b/media/video/capture/win/video_capture_device_mf_win.h deleted file mode 100644 index 6f229b05..0000000 --- a/media/video/capture/win/video_capture_device_mf_win.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Windows specific implementation of VideoCaptureDevice. -// DirectShow is used for capturing. DirectShow provide its own threads -// for capturing. - -#ifndef MEDIA_VIDEO_CAPTURE_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_ -#define MEDIA_VIDEO_CAPTURE_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_ - -#include <mfidl.h> -#include <mfreadwrite.h> - -#include <vector> - -#include "base/synchronization/lock.h" -#include "base/threading/non_thread_safe.h" -#include "base/win/scoped_comptr.h" -#include "media/video/capture/video_capture_device.h" - -interface IMFSourceReader; - -namespace media { - -class MFReaderCallback; - -class VideoCaptureDeviceMFWin - : public base::NonThreadSafe, - public VideoCaptureDevice { - public: - explicit VideoCaptureDeviceMFWin(const Name& device_name); - virtual ~VideoCaptureDeviceMFWin(); - - // Opens the device driver for this device. - // This function is used by the static VideoCaptureDevice::Create function. - bool Init(); - - // VideoCaptureDevice implementation. - virtual void Allocate(int width, - int height, - int frame_rate, - VideoCaptureDevice::EventHandler* observer) OVERRIDE; - virtual void Start() OVERRIDE; - virtual void Stop() OVERRIDE; - virtual void DeAllocate() OVERRIDE; - virtual const Name& device_name() OVERRIDE; - - static void GetDeviceNames(Names* device_names); - - // Captured a new video frame. - void OnIncomingCapturedFrame(const uint8* data, int length, - const base::Time& time_stamp); - - private: - void OnError(HRESULT hr); - - Name name_; - base::win::ScopedComPtr<IMFActivate> device_; - scoped_refptr<MFReaderCallback> callback_; - - base::Lock lock_; // Used to guard the below variables. - VideoCaptureDevice::EventHandler* observer_; - base::win::ScopedComPtr<IMFSourceReader> reader_; - bool capture_; - - DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceMFWin); -}; - -} // namespace media - -#endif // MEDIA_VIDEO_CAPTURE_WIN_VIDEO_CAPTURE_DEVICE_MF_WIN_H_ diff --git a/media/video/capture/win/video_capture_device_win.cc b/media/video/capture/win/video_capture_device_win.cc index 721fb25..5a587b5 100644 --- a/media/video/capture/win/video_capture_device_win.cc +++ b/media/video/capture/win/video_capture_device_win.cc @@ -10,8 +10,6 @@ #include "base/string_util.h" #include "base/sys_string_conversions.h" #include "base/win/scoped_variant.h" -#include "base/win/windows_version.h" -#include "media/video/capture/win/video_capture_device_mf_win.h" using base::win::ScopedComPtr; using base::win::ScopedVariant; @@ -144,39 +142,42 @@ void DeleteMediaType(AM_MEDIA_TYPE* mt) { } } -} // namespace - -namespace media { +// Help structure used for comparing video capture capabilities. +struct ResolutionDiff { + int capability_index; + int diff_height; + int diff_width; + int diff_frame_rate; + media::VideoCaptureCapability::Format color; +}; + +bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) { + return abs(item1.diff_height) < abs(item2.diff_height); +} -// static -void VideoCaptureDevice::GetDeviceNames(Names* device_names) { - if (base::win::GetVersion() >= base::win::VERSION_VISTA) { - VideoCaptureDeviceMFWin::GetDeviceNames(device_names); - } else { - VideoCaptureDeviceWin::GetDeviceNames(device_names); - } +bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { + return abs(item1.diff_width) < abs(item2.diff_width); } -// static -VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { - VideoCaptureDevice* ret = NULL; - if (base::win::GetVersion() >= base::win::VERSION_VISTA) { - scoped_ptr<VideoCaptureDeviceMFWin> device( - new VideoCaptureDeviceMFWin(device_name)); - if (device->Init()) - ret = device.release(); - } else { - scoped_ptr<VideoCaptureDeviceWin> device( - new VideoCaptureDeviceWin(device_name)); - if (device->Init()) - ret = device.release(); - } +bool CompareFrameRate(const ResolutionDiff& item1, + const ResolutionDiff& item2) { + return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate); +} - return ret; +bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) { + return (item1.color < item2.color); } -// static -void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { +} // namespace + +namespace media { + +// Name of a fake DirectShow filter that exist on computers with +// GTalk installed. +static const char kGoogleCameraAdapter[] = "google camera adapter"; + +// Gets the names of all video capture devices connected to this computer. +void VideoCaptureDevice::GetDeviceNames(Names* device_names) { DCHECK(device_names); ScopedComPtr<ICreateDevEnum> dev_enum; @@ -195,10 +196,6 @@ void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { device_names->clear(); - // Name of a fake DirectShow filter that exist on computers with - // GTalk installed. - static const char kGoogleCameraAdapter[] = "google camera adapter"; - // Enumerate all video capture devices. ScopedComPtr<IMoniker> moniker; int index = 0; @@ -244,6 +241,15 @@ void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { } } +VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { + VideoCaptureDeviceWin* self = new VideoCaptureDeviceWin(device_name); + if (self && self->Init()) + return self; + + delete self; + return NULL; +} + VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) : device_name_(device_name), state_(kIdle), @@ -332,11 +338,10 @@ void VideoCaptureDeviceWin::Allocate( return; observer_ = observer; - // Get the camera capability that best match the requested resolution. - const VideoCaptureCapabilityWin& found_capability = - capabilities_.GetBestMatchedCapability(width, height, frame_rate); - VideoCaptureCapability capability = found_capability; + const int capability_index = GetBestMatchedCapability(width, height, + frame_rate); + VideoCaptureCapability capability = capabilities_[capability_index]; // Reduce the frame rate if the requested frame rate is lower // than the capability. @@ -354,7 +359,7 @@ void VideoCaptureDeviceWin::Allocate( } // Get the windows capability from the capture device. - hr = stream_config->GetStreamCaps(found_capability.stream_index, &pmt, + hr = stream_config->GetStreamCaps(capability_index, &pmt, reinterpret_cast<BYTE*>(&caps)); if (SUCCEEDED(hr)) { if (pmt->formattype == FORMAT_VideoInfo) { @@ -521,7 +526,7 @@ bool VideoCaptureDeviceWin::CreateCapabilityMap() { if (media_type->majortype == MEDIATYPE_Video && media_type->formattype == FORMAT_VideoInfo) { - VideoCaptureCapabilityWin capability(i); + VideoCaptureCapability capability; REFERENCE_TIME time_per_frame = 0; VIDEOINFOHEADER* h = @@ -581,13 +586,79 @@ bool VideoCaptureDeviceWin::CreateCapabilityMap() { DVLOG(2) << "Device support unknown media type " << guid_str; continue; } - capabilities_.Add(capability); + capabilities_[i] = capability; } DeleteMediaType(media_type); media_type = NULL; } - return !capabilities_.empty(); + return capabilities_.size() > 0; +} + +// Loops through the list of capabilities and returns an index of the best +// matching capability. +// The algorithm prioritize height, width, frame rate and color format in that +// order. +int VideoCaptureDeviceWin::GetBestMatchedCapability(int requested_width, + int requested_height, + int requested_frame_rate) { + DCHECK(CalledOnValidThread()); + std::list<ResolutionDiff> diff_list; + + // Loop through the candidates to create a list of differentials between the + // requested resolution and the camera capability. + for (CapabilityMap::iterator iterator = capabilities_.begin(); + iterator != capabilities_.end(); + ++iterator) { + VideoCaptureCapability capability = iterator->second; + + ResolutionDiff diff; + diff.capability_index = iterator->first; + diff.diff_width = capability.width - requested_width; + diff.diff_height = capability.height - requested_height; + diff.diff_frame_rate = capability.frame_rate - requested_frame_rate; + diff.color = capability.color; + diff_list.push_back(diff); + } + + // Sort the best height candidates. + diff_list.sort(&CompareHeight); + int best_diff = diff_list.front().diff_height; + for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); + it != diff_list.end(); ++it) { + if (it->diff_height != best_diff) { + // Remove all candidates but the best. + diff_list.erase(it, diff_list.end()); + break; + } + } + + // Sort the best width candidates. + diff_list.sort(&CompareWidth); + best_diff = diff_list.front().diff_width; + for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); + it != diff_list.end(); ++it) { + if (it->diff_width != best_diff) { + // Remove all candidates but the best. + diff_list.erase(it, diff_list.end()); + break; + } + } + + // Sort the best frame rate candidates. + diff_list.sort(&CompareFrameRate); + best_diff = diff_list.front().diff_frame_rate; + for (std::list<ResolutionDiff>::iterator it = diff_list.begin(); + it != diff_list.end(); ++it) { + if (it->diff_frame_rate != best_diff) { + diff_list.erase(it, diff_list.end()); + break; + } + } + + // Decide the best color format. + diff_list.sort(&CompareColor); + return diff_list.front().capability_index; } void VideoCaptureDeviceWin::SetErrorState(const char* reason) { diff --git a/media/video/capture/win/video_capture_device_win.h b/media/video/capture/win/video_capture_device_win.h index 9e1f005..8a4f305 100644 --- a/media/video/capture/win/video_capture_device_win.h +++ b/media/video/capture/win/video_capture_device_win.h @@ -21,7 +21,6 @@ #include "base/win/scoped_comptr.h" #include "media/video/capture/video_capture_device.h" #include "media/video/capture/video_capture_types.h" -#include "media/video/capture/win/capability_list_win.h" #include "media/video/capture/win/sink_filter_win.h" #include "media/video/capture/win/sink_input_pin_win.h" @@ -49,8 +48,6 @@ class VideoCaptureDeviceWin virtual void DeAllocate() OVERRIDE; virtual const Name& device_name() OVERRIDE; - static void GetDeviceNames(Names* device_names); - private: enum InternalState { kIdle, // The device driver is opened but camera is not in use. @@ -59,11 +56,13 @@ class VideoCaptureDeviceWin kError // Error accessing HW functions. // User needs to recover by destroying the object. }; + typedef std::map<int, VideoCaptureCapability> CapabilityMap; // Implements SinkFilterObserver. virtual void FrameReceived(const uint8* buffer, int length); bool CreateCapabilityMap(); + int GetBestMatchedCapability(int width, int height, int frame_rate); void SetErrorState(const char* reason); Name device_name_; @@ -83,7 +82,7 @@ class VideoCaptureDeviceWin scoped_refptr<SinkFilter> sink_filter_; // Map of all capabilities this device support. - CapabilityList capabilities_; + CapabilityMap capabilities_; DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceWin); }; |