Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Unified Diff: media/video/capture/mac/video_capture_device_decklink_mac.mm

Issue 535983002: Mac Video Capture: Support for Blackmagic DeckLink SDK video capture. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@crbug408493__1__Enumerate_blackmagic_devices__2__branched_from_master
Patch Set: Rebase. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/video/capture/mac/video_capture_device_decklink_mac.mm
diff --git a/media/video/capture/mac/video_capture_device_decklink_mac.mm b/media/video/capture/mac/video_capture_device_decklink_mac.mm
index 2842543862c7f0d0f5281a8c6b0b5c3fab8f9527..f8c95bb68ac9a5e8071625a614a68cb1cc16cef9 100644
--- a/media/video/capture/mac/video_capture_device_decklink_mac.mm
+++ b/media/video/capture/mac/video_capture_device_decklink_mac.mm
@@ -7,38 +7,25 @@
#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> {
tommi (sloooow) - chröme 2014/09/05 09:24:22 if you create a special subclass that implements t
mcasas 2014/09/09 11:05:01 Acknowledged.
- 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());
- }
+namespace media {
- void Release() {
- if (ptr_ != NULL) {
- ptr_->Release();
- ptr_ = NULL;
- }
+// static
+float GetDisplayModeFrameRate(
+ const ScopedDeckLinkPtr<IDeckLinkDisplayMode>& display_mode) {
+ BMDTimeValue time_value, time_scale;
+ float display_mode_frame_rate = 0.0f;
+ if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK &&
+ time_value > 0) {
+ display_mode_frame_rate = static_cast<float>(time_scale) / time_value;
}
-};
-
-} // namespace
-
-namespace media {
+ // Interlaced formats are going to be marked as double the frame rate,
+ // which follows the general naming conventions.
+ if (display_mode->GetFieldDominance() == bmdLowerFieldFirst ||
+ display_mode->GetFieldDominance() == bmdUpperFieldFirst)
tommi (sloooow) - chröme 2014/09/05 09:24:21 {}
mcasas 2014/09/09 11:05:00 Done.
+ display_mode_frame_rate *= 2.0f;
+ return display_mode_frame_rate;
+}
//static
void VideoCaptureDeviceDeckLinkMac::EnumerateDevices(
@@ -110,21 +97,12 @@ void VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities(
while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
// IDeckLinkDisplayMode does not have information on pixel format, it
// 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(
+ const media::VideoCaptureFormat format(
gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()),
- frame_rate,
- pixel_format);
+ GetDisplayModeFrameRate(display_mode),
+ PIXEL_FORMAT_UNKNOWN);
supported_formats->push_back(format);
- DVLOG(2) << device.name() << " resolution: "
- << format.frame_size.ToString() << "@: " << format.frame_rate
- << ", pixel format: " << format.pixel_format;
+ DVLOG(2) << format.ToString();
display_mode.Release();
}
return;
@@ -132,18 +110,176 @@ void VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities(
}
VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac(
- const Name& device_name) {}
+ const Name& device_name)
+ : device_name_(device_name) {
+}
VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {}
void VideoCaptureDeviceDeckLinkMac::AllocateAndStart(
tommi (sloooow) - chröme 2014/09/05 09:24:21 add thread check
mcasas 2014/09/09 11:05:01 Done.
const VideoCaptureParams& params,
scoped_ptr<VideoCaptureDevice::Client> client) {
- NOTIMPLEMENTED();
+ scoped_refptr<IDeckLinkIterator> decklink_iter(
+ CreateDeckLinkIteratorInstance());
+ DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator";
+ if (!decklink_iter)
+ return;
+
+ while (decklink_iter->Next(decklink_.Receive()) == S_OK) {
+ CFStringRef device_model_name = NULL;
+ if ((decklink_->GetModelName(&device_model_name) == S_OK) ||
+ (device_name_.id() == base::SysCFStringRefToUTF8(device_model_name))) {
+ break;
+ }
+ decklink_.Release();
+ }
+ if (!decklink_) {
+ SetErrorState("Device id not found in the system");
+ return;
+ }
+
+ if (decklink_->QueryInterface(IID_IDeckLinkInput,
+ decklink_input_.ReceiveVoid()) != S_OK) {
+ SetErrorState("Error querying input interface.");
tommi (sloooow) - chröme 2014/09/05 09:24:21 should we release declink_ here in this case?
mcasas 2014/09/09 11:05:01 SetErrorState() will ping VCController->VideoCaptu
+ return;
+ }
+
+ ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter;
+ if (decklink_input_->GetDisplayModeIterator(display_mode_iter.Receive()) !=
+ S_OK) {
+ SetErrorState("Error creating Display Mode Iterator");
+ return;
tommi (sloooow) - chröme 2014/09/05 09:24:21 same here for decklink_ and decklink_input_. (same
mcasas 2014/09/09 11:05:01 See above.
+ }
+
+ ScopedDeckLinkPtr<IDeckLinkDisplayMode> chosen_display_mode;
+ ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode;
+ int min_diff = INT_MAX;
+ while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
+ const int diff = abs(display_mode->GetWidth() -
+ params.requested_format.frame_size.width()) +
+ abs(params.requested_format.frame_size.height() -
+ display_mode->GetHeight()) + fabs(params.requested_format.frame_rate -
+ GetDisplayModeFrameRate(display_mode));
+ if (diff < min_diff) {
+ chosen_display_mode = display_mode;
+ min_diff = diff;
+ }
+ display_mode.Release();
+ }
+ if (!chosen_display_mode) {
+ SetErrorState("Could not find a display mode");
+ return;
+ }
+#if !defined(NDEBUG)
+ CFStringRef format_name = NULL;
+ if (chosen_display_mode->GetName(&format_name) == S_OK)
+ DVLOG(1) << "Chosen format: " << base::SysCFStringRefToUTF8(format_name);
+#endif
+
+ // Enable video input. Configure for no input video format change detection,
+ // this in turn will disable calls to VideoInputFormatChanged().
+ if (decklink_input_->EnableVideoInput(chosen_display_mode->GetDisplayMode(),
+ bmdFormat8BitYUV, bmdVideoInputFlagDefault) != S_OK) {
+ SetErrorState("Could not select the video format we like.");
+ return;
+ }
+
+ client_ = client.Pass();
+ decklink_input_->SetCallback(this);
+ if (decklink_input_->StartStreams() != S_OK) {
+ SetErrorState("Could not start capturing");
+ return;
tommi (sloooow) - chröme 2014/09/05 09:24:21 nit: return statement not necessary - but we shoul
mcasas 2014/09/09 11:05:01 See above.
+ }
}
void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() {
- NOTIMPLEMENTED();
+ if (decklink_input_->StopStreams() != S_OK)
tommi (sloooow) - chröme 2014/09/05 09:24:21 add thread check first and also check these pointe
mcasas 2014/09/09 11:05:01 Done.
+ LogMessage("Problem stopping capture.");
+ decklink_input_->SetCallback(NULL);
+ decklink_input_->DisableVideoInput();
+}
+
+HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFormatChanged (
+ BMDVideoInputFormatChangedEvents notification_events,
+ IDeckLinkDisplayMode *new_display_mode,
+ BMDDetectedVideoInputFormatFlags detected_signal_flags) {
+ DVLOG(1) << __FUNCTION__;
tommi (sloooow) - chröme 2014/09/05 09:24:21 thread check?
mcasas 2014/09/09 11:05:00 Done.
+ return S_OK;
+}
+
+HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFrameArrived (
+ IDeckLinkVideoInputFrame* video_frame,
+ IDeckLinkAudioInputPacket* /* audio_packet */) {
+ // Capture frames are manipulated as an IDeckLinkVideoFrame.
tommi (sloooow) - chröme 2014/09/05 09:24:22 thread check?
mcasas 2014/09/09 11:05:01 Done.
+ void *videoData;
tommi (sloooow) - chröme 2014/09/05 09:24:21 void* video_data = NULL;
mcasas 2014/09/09 11:05:01 Done.
+ video_frame->GetBytes(&videoData);
+
+ VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN;
+ switch (video_frame->GetPixelFormat()) {
+ case bmdFormat8BitYUV: // A.k.a. '2vuy';
+ pixel_format = PIXEL_FORMAT_UYVY;
+ break;
+ case bmdFormat8BitARGB:
+ pixel_format = PIXEL_FORMAT_ARGB;
+ break;
+ default:
+ SetErrorState("Unsupported pixel format");
tommi (sloooow) - chröme 2014/09/05 09:24:21 add break; for posterity
mcasas 2014/09/09 11:05:01 Done.
+ }
+
+ const VideoCaptureFormat captureFormat(
tommi (sloooow) - chröme 2014/09/05 09:24:21 why captureFormat here and not capture_format? I
mcasas 2014/09/09 11:05:01 No, you're all right. The sample code(s) I followe
+ gfx::Size(video_frame->GetWidth(), video_frame->GetHeight()),
+ 0.0f, // Frame rate is not needed for captured data callback.
+ pixel_format);
+ client_->OnIncomingCapturedData(
+ static_cast<uint8*>(videoData),
+ video_frame->GetRowBytes() * video_frame->GetHeight(),
+ captureFormat,
+ 0, // Rotation.
+ base::TimeTicks::Now());
+
+ return S_OK;
+}
+
+HRESULT VideoCaptureDeviceDeckLinkMac::QueryInterface(REFIID iid, LPVOID *ppv) {
+ HRESULT result = E_NOINTERFACE;
+ *ppv = NULL;
tommi (sloooow) - chröme 2014/09/05 09:24:22 no need to do this
mcasas 2014/09/09 11:05:01 Acknowledged.
+ // Obtain the IUnknown interface and compare it the provided REFIID
tommi (sloooow) - chröme 2014/09/05 09:24:21 this isn't obtaining the interface itself, it's fe
mcasas 2014/09/09 11:05:00 Acknowledged.
+ CFUUIDBytes iunknown = CFUUIDGetUUIDBytes(IUnknownUUID);
+ if (memcmp(&iid, &iunknown, sizeof(REFIID)) == 0) {
+ *ppv = this;
+ AddRef();
+ result = S_OK;
+ } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback, sizeof(REFIID))
+ == 0) {
+ *ppv = (IDeckLinkNotificationCallback*)this;
tommi (sloooow) - chröme 2014/09/05 09:24:21 static_cast
mcasas 2014/09/09 11:05:00 Acknowledged.
+ AddRef();
+ result = S_OK;
+ }
+ return result;
tommi (sloooow) - chröme 2014/09/05 09:24:21 this implementation can be simplified: if (memcmp
mcasas 2014/09/09 11:05:01 Done.
+}
+
+ULONG VideoCaptureDeviceDeckLinkMac::AddRef(void) {
+ return OSAtomicIncrement32(&ref_count_);
tommi (sloooow) - chröme 2014/09/05 09:24:21 why atomic? Do we expect multithreaded access? (i
mcasas 2014/09/09 11:05:00 Reference/Example implementation says so :) Added
+}
+
+ULONG VideoCaptureDeviceDeckLinkMac::Release(void) {
+ int32_t newRefValue = OSAtomicDecrement32(&ref_count_);
+ if (newRefValue == 0) {
+ delete this;
+ return 0;
tommi (sloooow) - chröme 2014/09/05 09:24:21 nit: this return statement isn't necessary
mcasas 2014/09/09 11:05:01 Done.
+ }
+ return newRefValue;
+}
+
+
+void VideoCaptureDeviceDeckLinkMac::SetErrorState(const std::string& reason) {
+ if (client_)
+ client_->OnError(reason);
+}
+
+void VideoCaptureDeviceDeckLinkMac::LogMessage(const std::string& message) {
+ if (client_)
+ client_->OnLog(message);
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698