diff options
author | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-05 13:09:37 +0000 |
---|---|---|
committer | tommi@chromium.org <tommi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-05 13:09:37 +0000 |
commit | 9e6674e7d55f94056ba6d1556a3b8898e0b9eab8 (patch) | |
tree | 02bc154bb08b4af76331788bd1f4b0513614d2b9 /media/video | |
parent | 97bf552b5f4e9954cf94616696323a6a40452ac2 (diff) | |
download | chromium_src-9e6674e7d55f94056ba6d1556a3b8898e0b9eab8.zip chromium_src-9e6674e7d55f94056ba6d1556a3b8898e0b9eab8.tar.gz chromium_src-9e6674e7d55f94056ba6d1556a3b8898e0b9eab8.tar.bz2 |
Re-land https://codereview.chromium.org/11419200/
I had to revert the change since media and content unittests failed to load on the XP bots.
This modification to the above CL moves the MF delayload entries the chrome_dll.gyp over to media.gyp for all dependents.
Original CL description:
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).
TBR=mflodman@chromium.org,darin@chromium.org
Review URL: https://codereview.chromium.org/11442011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171212 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/video')
-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 |
6 files changed, 680 insertions, 115 deletions
diff --git a/media/video/capture/win/capability_list_win.cc b/media/video/capture/win/capability_list_win.cc new file mode 100644 index 0000000..63bd69b --- /dev/null +++ b/media/video/capture/win/capability_list_win.cc @@ -0,0 +1,114 @@ +// 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 new file mode 100644 index 0000000..6f96942 --- /dev/null +++ b/media/video/capture/win/capability_list_win.h @@ -0,0 +1,50 @@ +// 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 new file mode 100644 index 0000000..131bc7e --- /dev/null +++ b/media/video/capture/win/video_capture_device_mf_win.cc @@ -0,0 +1,399 @@ +// 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 new file mode 100644 index 0000000..6f229b05 --- /dev/null +++ b/media/video/capture/win/video_capture_device_mf_win.h @@ -0,0 +1,72 @@ +// 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 5a587b5..721fb25 100644 --- a/media/video/capture/win/video_capture_device_win.cc +++ b/media/video/capture/win/video_capture_device_win.cc @@ -10,6 +10,8 @@ #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; @@ -142,42 +144,39 @@ void DeleteMediaType(AM_MEDIA_TYPE* mt) { } } -// 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); -} - -bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { - return abs(item1.diff_width) < abs(item2.diff_width); -} +} // namespace -bool CompareFrameRate(const ResolutionDiff& item1, - const ResolutionDiff& item2) { - return abs(item1.diff_frame_rate) < abs(item2.diff_frame_rate); -} +namespace media { -bool CompareColor(const ResolutionDiff& item1, const ResolutionDiff& item2) { - return (item1.color < item2.color); +// static +void VideoCaptureDevice::GetDeviceNames(Names* device_names) { + if (base::win::GetVersion() >= base::win::VERSION_VISTA) { + VideoCaptureDeviceMFWin::GetDeviceNames(device_names); + } else { + VideoCaptureDeviceWin::GetDeviceNames(device_names); + } } -} // namespace - -namespace media { +// 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(); + } -// Name of a fake DirectShow filter that exist on computers with -// GTalk installed. -static const char kGoogleCameraAdapter[] = "google camera adapter"; + return ret; +} -// Gets the names of all video capture devices connected to this computer. -void VideoCaptureDevice::GetDeviceNames(Names* device_names) { +// static +void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { DCHECK(device_names); ScopedComPtr<ICreateDevEnum> dev_enum; @@ -196,6 +195,10 @@ void VideoCaptureDevice::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; @@ -241,15 +244,6 @@ void VideoCaptureDevice::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), @@ -338,10 +332,11 @@ void VideoCaptureDeviceWin::Allocate( return; observer_ = observer; + // Get the camera capability that best match the requested resolution. - const int capability_index = GetBestMatchedCapability(width, height, - frame_rate); - VideoCaptureCapability capability = capabilities_[capability_index]; + const VideoCaptureCapabilityWin& found_capability = + capabilities_.GetBestMatchedCapability(width, height, frame_rate); + VideoCaptureCapability capability = found_capability; // Reduce the frame rate if the requested frame rate is lower // than the capability. @@ -359,7 +354,7 @@ void VideoCaptureDeviceWin::Allocate( } // Get the windows capability from the capture device. - hr = stream_config->GetStreamCaps(capability_index, &pmt, + hr = stream_config->GetStreamCaps(found_capability.stream_index, &pmt, reinterpret_cast<BYTE*>(&caps)); if (SUCCEEDED(hr)) { if (pmt->formattype == FORMAT_VideoInfo) { @@ -526,7 +521,7 @@ bool VideoCaptureDeviceWin::CreateCapabilityMap() { if (media_type->majortype == MEDIATYPE_Video && media_type->formattype == FORMAT_VideoInfo) { - VideoCaptureCapability capability; + VideoCaptureCapabilityWin capability(i); REFERENCE_TIME time_per_frame = 0; VIDEOINFOHEADER* h = @@ -586,79 +581,13 @@ bool VideoCaptureDeviceWin::CreateCapabilityMap() { DVLOG(2) << "Device support unknown media type " << guid_str; continue; } - capabilities_[i] = capability; + capabilities_.Add(capability); } DeleteMediaType(media_type); media_type = NULL; } - 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; + return !capabilities_.empty(); } 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 8a4f305..9e1f005 100644 --- a/media/video/capture/win/video_capture_device_win.h +++ b/media/video/capture/win/video_capture_device_win.h @@ -21,6 +21,7 @@ #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" @@ -48,6 +49,8 @@ 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. @@ -56,13 +59,11 @@ 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_; @@ -82,7 +83,7 @@ class VideoCaptureDeviceWin scoped_refptr<SinkFilter> sink_filter_; // Map of all capabilities this device support. - CapabilityMap capabilities_; + CapabilityList capabilities_; DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureDeviceWin); }; |