Chromium Code Reviews| 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 7b07a9ea5afc754001d831baf7720f14e80d22a1..ff783ae797c78ffbfdfb34521d5845e21101c306 100644 |
| --- a/media/video/capture/mac/video_capture_device_decklink_mac.mm |
| +++ b/media/video/capture/mac/video_capture_device_decklink_mac.mm |
| @@ -7,36 +7,6 @@ |
| #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 { |
| @@ -115,6 +85,11 @@ void VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( |
| time_value > 0) { |
| frame_rate = static_cast<float>(time_scale) / time_value; |
| } |
| + // 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) |
| + frame_rate *= 2.0f; |
| media::VideoCaptureFormat format( |
|
magjed_chromium
2014/09/04 13:39:18
format can be made const
mcasas
2014/09/05 09:00:40
Done.
|
| gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()), |
| frame_rate, |
| @@ -130,18 +105,191 @@ void VideoCaptureDeviceDeckLinkMac::EnumerateDeviceCapabilities( |
| } |
| VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac( |
| - const Name& device_name) {} |
| + const Name& device_name) |
| + : device_name_(device_name) { |
| +} |
| VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {} |
| void VideoCaptureDeviceDeckLinkMac::AllocateAndStart( |
| 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."); |
| + return; |
| + } |
| + |
| + ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter; |
| + if (decklink_input_->GetDisplayModeIterator(display_mode_iter.Receive()) != |
| + S_OK) { |
| + SetErrorState("Error creating Display Mode Iterator"); |
| + return; |
| + } |
| + |
| + ScopedDeckLinkPtr<IDeckLinkDisplayMode> chosen_display_mode; |
| + ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode; |
| + int min_diff = INT_MAX; |
| + while (display_mode_iter->Next(display_mode.Receive()) == S_OK) { |
| + BMDTimeValue time_value, time_scale; |
| + float display_mode_frame_rate = 0.0f; |
| + if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK) |
| + display_mode_frame_rate = static_cast<float>(time_scale) / time_value; |
|
magjed_chromium
2014/09/04 13:39:18
Don't you need to check time_value > 0 here? Anywa
mcasas
2014/09/05 09:00:40
Done.
|
| + // 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) |
| + display_mode_frame_rate *= 2.0f; |
| + |
| + int diff = abs(display_mode->GetWidth() - |
|
magjed_chromium
2014/09/04 13:39:18
diff can be made const
mcasas
2014/09/05 09:00:40
Done.
|
| + params.requested_format.frame_size.width()) + |
| + abs(params.requested_format.frame_size.height() - |
| + display_mode->GetHeight()) + fabs(params.requested_format.frame_rate - |
| + display_mode_frame_rate); |
| + 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; |
| + } |
| } |
| void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() { |
| - NOTIMPLEMENTED(); |
| + if (decklink_input_->StopStreams() != S_OK) |
| + 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__; |
| + return S_OK; |
| +} |
| + |
| +HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFrameArrived ( |
| + IDeckLinkVideoInputFrame* video_frame, |
| + IDeckLinkAudioInputPacket* /* audio_packet */) { |
| + // Capture frames are manipulated as an IDeckLinkVideoFrame. |
| + void *videoData; |
| + 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; |
| + case bmdFormat8BitBGRA: |
|
magjed_chromium
2014/09/04 13:39:18
Why have you included this case if you don't do an
mcasas
2014/09/05 09:00:40
I guess eventually I wanted to do something but th
|
| + default: // All others are 10-bit pixel formats and we don't support them. |
| + SetErrorState("Unsupported pixel format"); |
| + } |
| + |
| + media::VideoCaptureFormat captureFormat( |
|
magjed_chromium
2014/09/04 13:39:18
captureFormat can be made const
mcasas
2014/09/05 09:00:40
Done.
|
| + 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) { |
| + CFUUIDBytes iunknown; |
| + HRESULT result = E_NOINTERFACE; |
| + *ppv = NULL; |
| + // Obtain the IUnknown interface and compare it the provided REFIID |
| + 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) { |
|
magjed_chromium
2014/09/04 13:39:18
you should align == 0 to memcmp
mcasas
2014/09/05 09:00:40
Done.
|
| + *ppv = (IDeckLinkNotificationCallback*)this; |
| + AddRef(); |
| + result = S_OK; |
| + } |
| + return result; |
| +} |
| + |
| +ULONG VideoCaptureDeviceDeckLinkMac::AddRef(void) { |
| + return OSAtomicIncrement32(&ref_count_); |
| +} |
| + |
| +ULONG VideoCaptureDeviceDeckLinkMac::Release(void) { |
| + int32_t newRefValue; |
| + |
| + newRefValue = OSAtomicDecrement32(&ref_count_); |
| + if (newRefValue == 0) { |
| + delete this; |
| + return 0; |
| + } |
| + |
| + 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 |