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

Side by Side 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: 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/video/capture/mac/video_capture_device_decklink_mac.h" 5 #include "media/video/capture/mac/video_capture_device_decklink_mac.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/memory/ref_counted.h" 8 #include "base/memory/ref_counted.h"
9 #include "base/strings/sys_string_conversions.h" 9 #include "base/strings/sys_string_conversions.h"
10 #include "third_party/decklink/mac/include/DeckLinkAPI.h"
11
12 namespace {
13
14 // DeckLink SDK uses ScopedComPtr-style APIs. Chrome ScopedComPtr is only
15 // available for Windows builds. This is a verbatim knock-off of the needed
16 // parts of base::win::ScopedComPtr<> for ref counting.
17 template <class T>
18 class ScopedDeckLinkPtr : public scoped_refptr<T> {
19 public:
20 using scoped_refptr<T>::ptr_;
21
22 T** Receive() {
23 DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
24 return &ptr_;
25 }
26
27 void** ReceiveVoid() {
28 return reinterpret_cast<void**>(Receive());
29 }
30
31 void Release() {
32 if (ptr_ != NULL) {
33 ptr_->Release();
34 ptr_ = NULL;
35 }
36 }
37 };
38
39 } // namespace
40 10
41 namespace media { 11 namespace media {
42 12
43 //static 13 //static
44 void VideoCaptureDeviceDeckLinkMac::EnumerateDevices( 14 void VideoCaptureDeviceDeckLinkMac::EnumerateDevices(
45 VideoCaptureDevice::Names* device_names) { 15 VideoCaptureDevice::Names* device_names) {
46 scoped_refptr<IDeckLinkIterator> decklink_iter( 16 scoped_refptr<IDeckLinkIterator> decklink_iter(
47 CreateDeckLinkIteratorInstance()); 17 CreateDeckLinkIteratorInstance());
48 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator"; 18 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator";
49 if (!decklink_iter) 19 if (!decklink_iter)
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter; 71 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter;
102 if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) != 72 if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) !=
103 S_OK) { 73 S_OK) {
104 continue; 74 continue;
105 } 75 }
106 76
107 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode; 77 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode;
108 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) { 78 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
109 // IDeckLinkDisplayMode does not have information on pixel format, it 79 // IDeckLinkDisplayMode does not have information on pixel format, it
110 // is only available on capture. 80 // is only available on capture.
111 media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN; 81 media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN;
magjed_chromium 2014/09/04 13:39:18 Why do you need to declare this variable? Why not
mcasas 2014/09/05 09:00:40 Done.
112 BMDTimeValue time_value, time_scale; 82 BMDTimeValue time_value, time_scale;
113 float frame_rate = 0.0f; 83 float frame_rate = 0.0f;
114 if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK && 84 if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK &&
115 time_value > 0) { 85 time_value > 0) {
116 frame_rate = static_cast<float>(time_scale) / time_value; 86 frame_rate = static_cast<float>(time_scale) / time_value;
117 } 87 }
88 // Interlaced formats are going to be marked as double the frame rate,
89 // which follows the general naming conventions.
90 if (display_mode->GetFieldDominance() == bmdLowerFieldFirst ||
91 display_mode->GetFieldDominance() == bmdUpperFieldFirst)
92 frame_rate *= 2.0f;
118 media::VideoCaptureFormat format( 93 media::VideoCaptureFormat format(
magjed_chromium 2014/09/04 13:39:18 format can be made const
mcasas 2014/09/05 09:00:40 Done.
119 gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()), 94 gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()),
120 frame_rate, 95 frame_rate,
121 pixel_format); 96 pixel_format);
122 supported_formats->push_back(format); 97 supported_formats->push_back(format);
123 DVLOG(2) << device.name() << " resolution: " 98 DVLOG(2) << device.name() << " resolution: "
124 << format.frame_size.ToString() << "@: " << format.frame_rate 99 << format.frame_size.ToString() << "@: " << format.frame_rate
125 << ", pixel format: " << format.pixel_format; 100 << ", pixel format: " << format.pixel_format;
126 display_mode.Release(); 101 display_mode.Release();
127 } 102 }
128 return; 103 return;
129 } 104 }
130 } 105 }
131 106
132 VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac( 107 VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac(
133 const Name& device_name) {} 108 const Name& device_name)
109 : device_name_(device_name) {
110 }
134 111
135 VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {} 112 VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {}
136 113
137 void VideoCaptureDeviceDeckLinkMac::AllocateAndStart( 114 void VideoCaptureDeviceDeckLinkMac::AllocateAndStart(
138 const VideoCaptureParams& params, 115 const VideoCaptureParams& params,
139 scoped_ptr<VideoCaptureDevice::Client> client) { 116 scoped_ptr<VideoCaptureDevice::Client> client) {
140 NOTIMPLEMENTED(); 117 scoped_refptr<IDeckLinkIterator> decklink_iter(
118 CreateDeckLinkIteratorInstance());
119 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator";
120 if (!decklink_iter)
121 return;
122
123 while (decklink_iter->Next(decklink_.Receive()) == S_OK) {
124 CFStringRef device_model_name = NULL;
125 if ((decklink_->GetModelName(&device_model_name) == S_OK) ||
126 (device_name_.id() == base::SysCFStringRefToUTF8(device_model_name))) {
127 break;
128 }
129 decklink_.Release();
130 }
131 if (!decklink_) {
132 SetErrorState("Device id not found in the system");
133 return;
134 }
135
136 if (decklink_->QueryInterface(IID_IDeckLinkInput,
137 decklink_input_.ReceiveVoid()) != S_OK) {
138 SetErrorState("Error querying input interface.");
139 return;
140 }
141
142 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter;
143 if (decklink_input_->GetDisplayModeIterator(display_mode_iter.Receive()) !=
144 S_OK) {
145 SetErrorState("Error creating Display Mode Iterator");
146 return;
147 }
148
149 ScopedDeckLinkPtr<IDeckLinkDisplayMode> chosen_display_mode;
150 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode;
151 int min_diff = INT_MAX;
152 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
153 BMDTimeValue time_value, time_scale;
154 float display_mode_frame_rate = 0.0f;
155 if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK)
156 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.
157 // Interlaced formats are going to be marked as double the frame rate,
158 // which follows the general naming conventions.
159 if (display_mode->GetFieldDominance() == bmdLowerFieldFirst ||
160 display_mode->GetFieldDominance() == bmdUpperFieldFirst)
161 display_mode_frame_rate *= 2.0f;
162
163 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.
164 params.requested_format.frame_size.width()) +
165 abs(params.requested_format.frame_size.height() -
166 display_mode->GetHeight()) + fabs(params.requested_format.frame_rate -
167 display_mode_frame_rate);
168 if (diff < min_diff) {
169 chosen_display_mode = display_mode;
170 min_diff = diff;
171 }
172 display_mode.Release();
173 }
174 if (!chosen_display_mode) {
175 SetErrorState("Could not find a display mode");
176 return;
177 }
178 #if !defined(NDEBUG)
179 CFStringRef format_name = NULL;
180 if (chosen_display_mode->GetName(&format_name) == S_OK)
181 DVLOG(1) << "Chosen format: " << base::SysCFStringRefToUTF8(format_name);
182 #endif
183
184 // Enable video input. Configure for no input video format change detection,
185 // this in turn will disable calls to VideoInputFormatChanged().
186 if (decklink_input_->EnableVideoInput(chosen_display_mode->GetDisplayMode(),
187 bmdFormat8BitYUV, bmdVideoInputFlagDefault) != S_OK) {
188 SetErrorState("Could not select the video format we like.");
189 return;
190 }
191
192 client_ = client.Pass();
193 decklink_input_->SetCallback(this);
194 if (decklink_input_->StartStreams() != S_OK) {
195 SetErrorState("Could not start capturing");
196 return;
197 }
141 } 198 }
142 199
143 void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() { 200 void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() {
144 NOTIMPLEMENTED(); 201 if (decklink_input_->StopStreams() != S_OK)
202 LogMessage("Problem stopping capture.");
203 decklink_input_->SetCallback(NULL);
204 decklink_input_->DisableVideoInput();
205 }
206
207 HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFormatChanged (
208 BMDVideoInputFormatChangedEvents notification_events,
209 IDeckLinkDisplayMode *new_display_mode,
210 BMDDetectedVideoInputFormatFlags detected_signal_flags) {
211 DVLOG(1) << __FUNCTION__;
212 return S_OK;
213 }
214
215 HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFrameArrived (
216 IDeckLinkVideoInputFrame* video_frame,
217 IDeckLinkAudioInputPacket* /* audio_packet */) {
218 // Capture frames are manipulated as an IDeckLinkVideoFrame.
219 void *videoData;
220 video_frame->GetBytes(&videoData);
221
222 VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN;
223 switch (video_frame->GetPixelFormat()) {
224 case bmdFormat8BitYUV: // A.k.a. '2vuy';
225 pixel_format = PIXEL_FORMAT_UYVY;
226 break;
227 case bmdFormat8BitARGB:
228 pixel_format = PIXEL_FORMAT_ARGB;
229 break;
230 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
231 default: // All others are 10-bit pixel formats and we don't support them.
232 SetErrorState("Unsupported pixel format");
233 }
234
235 media::VideoCaptureFormat captureFormat(
magjed_chromium 2014/09/04 13:39:18 captureFormat can be made const
mcasas 2014/09/05 09:00:40 Done.
236 gfx::Size(video_frame->GetWidth(), video_frame->GetHeight()),
237 0.0f, // Frame rate is not needed for captured data callback.
238 pixel_format);
239 client_->OnIncomingCapturedData(
240 static_cast<uint8*>(videoData),
241 video_frame->GetRowBytes() * video_frame->GetHeight(),
242 captureFormat,
243 0, // Rotation.
244 base::TimeTicks::Now());
245
246 return S_OK;
247 }
248
249 HRESULT VideoCaptureDeviceDeckLinkMac::QueryInterface(REFIID iid, LPVOID *ppv) {
250 CFUUIDBytes iunknown;
251 HRESULT result = E_NOINTERFACE;
252 *ppv = NULL;
253 // Obtain the IUnknown interface and compare it the provided REFIID
254 iunknown = CFUUIDGetUUIDBytes(IUnknownUUID);
255 if (memcmp(&iid, &iunknown, sizeof(REFIID)) == 0) {
256 *ppv = this;
257 AddRef();
258 result = S_OK;
259 } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback, sizeof(REFIID))
260 == 0) {
magjed_chromium 2014/09/04 13:39:18 you should align == 0 to memcmp
mcasas 2014/09/05 09:00:40 Done.
261 *ppv = (IDeckLinkNotificationCallback*)this;
262 AddRef();
263 result = S_OK;
264 }
265 return result;
266 }
267
268 ULONG VideoCaptureDeviceDeckLinkMac::AddRef(void) {
269 return OSAtomicIncrement32(&ref_count_);
270 }
271
272 ULONG VideoCaptureDeviceDeckLinkMac::Release(void) {
273 int32_t newRefValue;
274
275 newRefValue = OSAtomicDecrement32(&ref_count_);
276 if (newRefValue == 0) {
277 delete this;
278 return 0;
279 }
280
281 return newRefValue;
282 }
283
284
285 void VideoCaptureDeviceDeckLinkMac::SetErrorState(const std::string& reason) {
286 if (client_)
287 client_->OnError(reason);
288 }
289
290 void VideoCaptureDeviceDeckLinkMac::LogMessage(const std::string& message) {
291 if (client_)
292 client_->OnLog(message);
145 } 293 }
146 294
147 } // namespace media 295 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698