diff options
author | mcasas <mcasas@chromium.org> | 2014-09-22 05:28:42 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-09-22 12:28:59 +0000 |
commit | 9b46fe6874291e1e50c9230b720293932dea6231 (patch) | |
tree | e1a48e3387e2e57ccf7de766c59afffa98e02266 /media | |
parent | 9eed34b6e693049a62c5ce3eb7830705df6f9bbd (diff) | |
download | chromium_src-9b46fe6874291e1e50c9230b720293932dea6231.zip chromium_src-9b46fe6874291e1e50c9230b720293932dea6231.tar.gz chromium_src-9b46fe6874291e1e50c9230b720293932dea6231.tar.bz2 |
Mac VideoCapture: Support for Blackmagic DeckLink device & capabilities enumeration, using SDK.
This CL adds a new class VideoCaptureDeviceDeckLinkMac with
two static methods EnumerateDevices() and
EnumerateDeviceCapabilities(). This class also has some
empty methods to comply with VCD interface.
DeckLink uses ScopedComPtr style APIs, so an internal
template class is provided with the needed bits for automatic
reference counting inside VCDDeckLinkMac.
Static methods for enumeration are used from VCDFactoryMac.
Support for Blackmagic SDK as a third party is discussed in
http://crbug.com/408534 and is necessary prerequisite
for landing this CL. This SDK landing is under review in
http://crrev.com/509313002.
Other CL(s) will follow to use DeckLink devices for capture.
BUG=408493, 408534
Review URL: https://codereview.chromium.org/518073002
Cr-Commit-Position: refs/heads/master@{#295952}
Diffstat (limited to 'media')
-rw-r--r-- | media/BUILD.gn | 3 | ||||
-rw-r--r-- | media/media.gyp | 5 | ||||
-rw-r--r-- | media/video/capture/mac/DEPS | 3 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_avfoundation_mac.mm | 4 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_decklink_mac.h | 46 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_decklink_mac.mm | 183 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_factory_mac.mm | 18 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_mac.mm | 2 | ||||
-rw-r--r-- | media/video/capture/video_capture_device.h | 1 |
9 files changed, 261 insertions, 4 deletions
diff --git a/media/BUILD.gn b/media/BUILD.gn index 9665932..287b230 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -165,6 +165,8 @@ component("media") { "video/capture/mac/platform_video_capturing_mac.h", "video/capture/mac/video_capture_device_avfoundation_mac.h", "video/capture/mac/video_capture_device_avfoundation_mac.mm", + "video/capture/mac/video_capture_device_decklink_mac.h", + "video/capture/mac/video_capture_device_decklink_mac.mm", "video/capture/mac/video_capture_device_factory_mac.h", "video/capture/mac/video_capture_device_factory_mac.mm", "video/capture/mac/video_capture_device_mac.h", @@ -333,6 +335,7 @@ component("media") { if (is_mac) { deps += [ "//media/base/mac", + "//third_party/decklink", ] libs += [ "CoreMIDI.framework", diff --git a/media/media.gyp b/media/media.gyp index 5f4bca9..59dd356 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -504,6 +504,8 @@ 'video/capture/mac/platform_video_capturing_mac.h', 'video/capture/mac/video_capture_device_avfoundation_mac.h', 'video/capture/mac/video_capture_device_avfoundation_mac.mm', + 'video/capture/mac/video_capture_device_decklink_mac.h', + 'video/capture/mac/video_capture_device_decklink_mac.mm', 'video/capture/mac/video_capture_device_factory_mac.h', 'video/capture/mac/video_capture_device_factory_mac.mm', 'video/capture/mac/video_capture_device_mac.h', @@ -873,6 +875,9 @@ ], }], ['OS=="mac"', { + 'dependencies': [ + '../third_party/decklink/decklink.gyp:decklink', + ], 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/AudioToolbox.framework', diff --git a/media/video/capture/mac/DEPS b/media/video/capture/mac/DEPS new file mode 100644 index 0000000..58a1003 --- /dev/null +++ b/media/video/capture/mac/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+third_party/decklink", +] diff --git a/media/video/capture/mac/video_capture_device_avfoundation_mac.mm b/media/video/capture/mac/video_capture_device_avfoundation_mac.mm index 823f889..47ae1ef 100644 --- a/media/video/capture/mac/video_capture_device_avfoundation_mac.mm +++ b/media/video/capture/mac/video_capture_device_avfoundation_mac.mm @@ -70,11 +70,11 @@ break; } - CoreMediaGlue::CMVideoDimensions dimensions = + CoreMediaGlue::CMVideoDimensions dimensions = CoreMediaGlue::CMVideoFormatDescriptionGetDimensions( [format formatDescription]); - for (CrAVFrameRateRange* frameRate in + for (CrAVFrameRateRange* frameRate in [format videoSupportedFrameRateRanges]) { media::VideoCaptureFormat format( gfx::Size(dimensions.width, dimensions.height), diff --git a/media/video/capture/mac/video_capture_device_decklink_mac.h b/media/video/capture/mac/video_capture_device_decklink_mac.h new file mode 100644 index 0000000..8fadc18 --- /dev/null +++ b/media/video/capture/mac/video_capture_device_decklink_mac.h @@ -0,0 +1,46 @@ +// Copyright 2014 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. + +// Implementation of VideoCaptureDevice class for Blackmagic video capture +// devices by using the DeckLink SDK. + +#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_DECKLINK_MAC_H_ +#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_DECKLINK_MAC_H_ + +#include "media/video/capture/video_capture_device.h" + +#import <Foundation/Foundation.h> + +namespace media { + +// Extension of VideoCaptureDevice to create and manipulate Blackmagic devices +// via DeckLink SDK. +class MEDIA_EXPORT VideoCaptureDeviceDeckLinkMac : public VideoCaptureDevice { + public: + // Gets the names of all DeckLink video capture devices connected to this + // computer, as enumerated by the DeckLink SDK. + static void EnumerateDevices(VideoCaptureDevice::Names* device_names); + + // Gets the supported formats of a particular device attached to the system, + // identified by |device|. Formats are retrieved from the DeckLink SDK. + static void EnumerateDeviceCapabilities( + const VideoCaptureDevice::Name& device, + VideoCaptureFormats* supported_formats); + + explicit VideoCaptureDeviceDeckLinkMac(const Name& device_name); + virtual ~VideoCaptureDeviceDeckLinkMac(); + + // VideoCaptureDevice implementation. + virtual void AllocateAndStart( + const VideoCaptureParams& params, + scoped_ptr<VideoCaptureDevice::Client> client) OVERRIDE; + virtual void StopAndDeAllocate() OVERRIDE; + + private: + DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceDeckLinkMac); +}; + +} // namespace media + +#endif // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_DECKLINK_MAC_H_ diff --git a/media/video/capture/mac/video_capture_device_decklink_mac.mm b/media/video/capture/mac/video_capture_device_decklink_mac.mm new file mode 100644 index 0000000..57c2c02 --- /dev/null +++ b/media/video/capture/mac/video_capture_device_decklink_mac.mm @@ -0,0 +1,183 @@ +// Copyright 2014 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/mac/video_capture_device_decklink_mac.h" + +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/strings/sys_string_conversions.h" +#include "third_party/decklink/mac/include/DeckLinkAPI.h" + +namespace { + +// DeckLink SDK uses ScopedComPtr-style APIs. Chrome ScopedComPtr is only +// available for Windows builds. This is a verbatim knock-off of the needed +// parts of base::win::ScopedComPtr<> for ref counting. +template <class T> +class ScopedDeckLinkPtr : public scoped_refptr<T> { + public: + using scoped_refptr<T>::ptr_; + + T** Receive() { + DCHECK(!ptr_) << "Object leak. Pointer must be NULL"; + return &ptr_; + } + + void** ReceiveVoid() { + return reinterpret_cast<void**>(Receive()); + } + + void Release() { + if (ptr_ != NULL) { + ptr_->Release(); + ptr_ = NULL; + } + } +}; + +} // namespace + +namespace media { + +std::string JoinDeviceNameAndFormat(CFStringRef name, CFStringRef format) { + return base::SysCFStringRefToUTF8(name) + " - " + + base::SysCFStringRefToUTF8(format); +} + +//static +void VideoCaptureDeviceDeckLinkMac::EnumerateDevices( + VideoCaptureDevice::Names* device_names) { + scoped_refptr<IDeckLinkIterator> decklink_iter( + CreateDeckLinkIteratorInstance()); + // At this point, not being able to create a DeckLink iterator means that + // there are no Blackmagic devices in the system but this isn't an error. + DVLOG_IF(1, !decklink_iter.get()) << "Could not create DeckLink iterator"; + if (!decklink_iter.get()) + return; + + ScopedDeckLinkPtr<IDeckLink> decklink; + while (decklink_iter->Next(decklink.Receive()) == S_OK) { + ScopedDeckLinkPtr<IDeckLink> decklink_local; + decklink_local.swap(decklink); + + CFStringRef device_model_name = NULL; + HRESULT hr = decklink_local->GetModelName(&device_model_name); + DVLOG_IF(1, hr != S_OK) << "Error reading Blackmagic device model name"; + CFStringRef device_display_name = NULL; + hr = decklink_local->GetDisplayName(&device_display_name); + DVLOG_IF(1, hr != S_OK) << "Error reading Blackmagic device display name"; + DVLOG_IF(1, hr == S_OK) << "Blackmagic device found with name: " << + base::SysCFStringRefToUTF8(device_display_name); + + if (!device_model_name && !device_display_name) + continue; + + ScopedDeckLinkPtr<IDeckLinkInput> decklink_input; + if (decklink_local->QueryInterface(IID_IDeckLinkInput, + decklink_input.ReceiveVoid()) != S_OK) { + DLOG(ERROR) << "Error Blackmagic querying input interface."; + return; + } + + ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter; + if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) != + S_OK) { + continue; + } + + ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode; + while (display_mode_iter->Next(display_mode.Receive()) == S_OK) { + CFStringRef format_name = NULL; + if (display_mode->GetName(&format_name) == S_OK) { + VideoCaptureDevice::Name name( + JoinDeviceNameAndFormat(device_display_name, format_name), + JoinDeviceNameAndFormat(device_model_name, format_name), + VideoCaptureDevice::Name::DECKLINK, + VideoCaptureDevice::Name::OTHER_TRANSPORT); + device_names->push_back(name); + DVLOG(1) << "Blackmagic camera enumerated: " << name.name(); + } + display_mode.Release(); + } + } +} + +// static +void VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( + const VideoCaptureDevice::Name& device, + VideoCaptureFormats* supported_formats) { + scoped_refptr<IDeckLinkIterator> decklink_iter( + CreateDeckLinkIteratorInstance()); + DLOG_IF(ERROR, !decklink_iter.get()) << "Error creating DeckLink iterator"; + if (!decklink_iter.get()) + return; + + ScopedDeckLinkPtr<IDeckLink> decklink; + while (decklink_iter->Next(decklink.Receive()) == S_OK) { + ScopedDeckLinkPtr<IDeckLink> decklink_local; + decklink_local.swap(decklink); + + ScopedDeckLinkPtr<IDeckLinkInput> decklink_input; + if (decklink_local->QueryInterface(IID_IDeckLinkInput, + decklink_input.ReceiveVoid()) != S_OK) { + DLOG(ERROR) << "Error Blackmagic querying input interface."; + return; + } + + ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter; + if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) != + S_OK) { + continue; + } + + CFStringRef device_model_name = NULL; + if (decklink_local->GetModelName(&device_model_name) != S_OK) + continue; + + ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode; + while (display_mode_iter->Next(display_mode.Receive()) == S_OK) { + CFStringRef format_name = NULL; + if (display_mode->GetName(&format_name) == S_OK && device.id() != + JoinDeviceNameAndFormat(device_model_name, format_name)) { + display_mode.Release(); + continue; + } + + // IDeckLinkDisplayMode does not have information on pixel format, this + // is only available on capture. + media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN; + BMDTimeValue time_value, time_scale; + float frame_rate = 0.0f; + if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK && + time_value > 0) { + frame_rate = static_cast<float>(time_scale) / time_value; + } + media::VideoCaptureFormat format( + gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()), + frame_rate, + pixel_format); + supported_formats->push_back(format); + DVLOG(2) << device.name() << " " << format.ToString(); + display_mode.Release(); + } + return; + } +} + +VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac( + const Name& device_name) {} + +VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {} + +void VideoCaptureDeviceDeckLinkMac::AllocateAndStart( + const VideoCaptureParams& params, + scoped_ptr<VideoCaptureDevice::Client> client) { + NOTIMPLEMENTED(); +} + +void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() { + NOTIMPLEMENTED(); +} + +} // namespace media diff --git a/media/video/capture/mac/video_capture_device_factory_mac.mm b/media/video/capture/mac/video_capture_device_factory_mac.mm index f383b42..1fd4ecf 100644 --- a/media/video/capture/mac/video_capture_device_factory_mac.mm +++ b/media/video/capture/mac/video_capture_device_factory_mac.mm @@ -13,6 +13,7 @@ #import "media/base/mac/avfoundation_glue.h" #import "media/video/capture/mac/video_capture_device_avfoundation_mac.h" #include "media/video/capture/mac/video_capture_device_mac.h" +#import "media/video/capture/mac/video_capture_device_decklink_mac.h" #import "media/video/capture/mac/video_capture_device_qtkit_mac.h" namespace media { @@ -157,6 +158,9 @@ void VideoCaptureDeviceFactoryMac::GetDeviceNames( } } } + + // Also retrieve Blackmagic devices, if present, via DeckLink SDK API. + VideoCaptureDeviceDeckLinkMac::EnumerateDevices(device_names); } else { // We should not enumerate QTKit devices in Device Thread; NOTREACHED(); @@ -185,11 +189,13 @@ void VideoCaptureDeviceFactoryMac::GetDeviceSupportedFormats( const VideoCaptureDevice::Name& device, VideoCaptureFormats* supported_formats) { DCHECK(thread_checker_.CalledOnValidThread()); - if (device.capture_api_type() == VideoCaptureDevice::Name::AVFOUNDATION) { + switch (device.capture_api_type()) { + case VideoCaptureDevice::Name::AVFOUNDATION: DVLOG(1) << "Enumerating video capture capabilities, AVFoundation"; [VideoCaptureDeviceAVFoundation getDevice:device supportedFormats:supported_formats]; - } else { + break; + case VideoCaptureDevice::Name::QTKIT: // Blacklisted cameras provide their own supported format(s), otherwise no // such information is provided for QTKit. if (device.is_blacklisted()) { @@ -205,6 +211,14 @@ void VideoCaptureDeviceFactoryMac::GetDeviceSupportedFormats( } } } + break; + case VideoCaptureDevice::Name::DECKLINK: + DVLOG(1) << "Enumerating video capture capabilities " << device.name(); + VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( + device, supported_formats); + break; + default: + NOTREACHED(); } } diff --git a/media/video/capture/mac/video_capture_device_mac.mm b/media/video/capture/mac/video_capture_device_mac.mm index 882c152..190f53d 100644 --- a/media/video/capture/mac/video_capture_device_mac.mm +++ b/media/video/capture/mac/video_capture_device_mac.mm @@ -331,6 +331,8 @@ const std::string VideoCaptureDevice::Name::GetModel() const { // Skip the AVFoundation's not USB nor built-in devices. if (capture_api_type() == AVFOUNDATION && transport_type() != USB_OR_BUILT_IN) return ""; + if (capture_api_type() == DECKLINK) + return ""; // Both PID and VID are 4 characters. if (unique_id_.size() < 2 * kVidPidSize) return ""; diff --git a/media/video/capture/video_capture_device.h b/media/video/capture/video_capture_device.h index dfb12bd..17af0bc 100644 --- a/media/video/capture/video_capture_device.h +++ b/media/video/capture/video_capture_device.h @@ -55,6 +55,7 @@ class MEDIA_EXPORT VideoCaptureDevice { enum CaptureApiType { AVFOUNDATION, QTKIT, + DECKLINK, API_TYPE_UNKNOWN }; // For AVFoundation Api, identify devices that are built-in or USB. |