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

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: 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 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> {
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.
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
13 // static
14 float GetDisplayModeFrameRate(
15 const ScopedDeckLinkPtr<IDeckLinkDisplayMode>& display_mode) {
16 BMDTimeValue time_value, time_scale;
17 float display_mode_frame_rate = 0.0f;
18 if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK &&
19 time_value > 0) {
20 display_mode_frame_rate = static_cast<float>(time_scale) / time_value;
21 }
22 // Interlaced formats are going to be marked as double the frame rate,
23 // which follows the general naming conventions.
24 if (display_mode->GetFieldDominance() == bmdLowerFieldFirst ||
25 display_mode->GetFieldDominance() == bmdUpperFieldFirst)
tommi (sloooow) - chröme 2014/09/05 09:24:21 {}
mcasas 2014/09/09 11:05:00 Done.
26 display_mode_frame_rate *= 2.0f;
27 return display_mode_frame_rate;
28 }
29
43 //static 30 //static
44 void VideoCaptureDeviceDeckLinkMac::EnumerateDevices( 31 void VideoCaptureDeviceDeckLinkMac::EnumerateDevices(
45 VideoCaptureDevice::Names* device_names) { 32 VideoCaptureDevice::Names* device_names) {
46 scoped_refptr<IDeckLinkIterator> decklink_iter( 33 scoped_refptr<IDeckLinkIterator> decklink_iter(
47 CreateDeckLinkIteratorInstance()); 34 CreateDeckLinkIteratorInstance());
48 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator"; 35 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator";
49 if (!decklink_iter) 36 if (!decklink_iter)
50 return; 37 return;
51 38
52 ScopedDeckLinkPtr<IDeckLink> decklink; 39 ScopedDeckLinkPtr<IDeckLink> decklink;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter; 90 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter;
104 if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) != 91 if (decklink_input->GetDisplayModeIterator(display_mode_iter.Receive()) !=
105 S_OK) { 92 S_OK) {
106 continue; 93 continue;
107 } 94 }
108 95
109 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode; 96 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode;
110 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) { 97 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
111 // IDeckLinkDisplayMode does not have information on pixel format, it 98 // IDeckLinkDisplayMode does not have information on pixel format, it
112 // is only available on capture. 99 // is only available on capture.
113 media::VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN; 100 const media::VideoCaptureFormat format(
114 BMDTimeValue time_value, time_scale;
115 float frame_rate = 0.0f;
116 if (display_mode->GetFrameRate(&time_value, &time_scale) == S_OK &&
117 time_value > 0) {
118 frame_rate = static_cast<float>(time_scale) / time_value;
119 }
120 media::VideoCaptureFormat format(
121 gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()), 101 gfx::Size(display_mode->GetWidth(), display_mode->GetHeight()),
122 frame_rate, 102 GetDisplayModeFrameRate(display_mode),
123 pixel_format); 103 PIXEL_FORMAT_UNKNOWN);
124 supported_formats->push_back(format); 104 supported_formats->push_back(format);
125 DVLOG(2) << device.name() << " resolution: " 105 DVLOG(2) << format.ToString();
126 << format.frame_size.ToString() << "@: " << format.frame_rate
127 << ", pixel format: " << format.pixel_format;
128 display_mode.Release(); 106 display_mode.Release();
129 } 107 }
130 return; 108 return;
131 } 109 }
132 } 110 }
133 111
134 VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac( 112 VideoCaptureDeviceDeckLinkMac::VideoCaptureDeviceDeckLinkMac(
135 const Name& device_name) {} 113 const Name& device_name)
114 : device_name_(device_name) {
115 }
136 116
137 VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {} 117 VideoCaptureDeviceDeckLinkMac::~VideoCaptureDeviceDeckLinkMac() {}
138 118
139 void VideoCaptureDeviceDeckLinkMac::AllocateAndStart( 119 void VideoCaptureDeviceDeckLinkMac::AllocateAndStart(
tommi (sloooow) - chröme 2014/09/05 09:24:21 add thread check
mcasas 2014/09/09 11:05:01 Done.
140 const VideoCaptureParams& params, 120 const VideoCaptureParams& params,
141 scoped_ptr<VideoCaptureDevice::Client> client) { 121 scoped_ptr<VideoCaptureDevice::Client> client) {
142 NOTIMPLEMENTED(); 122 scoped_refptr<IDeckLinkIterator> decklink_iter(
123 CreateDeckLinkIteratorInstance());
124 DLOG_IF(ERROR, !decklink_iter) << "Error creating DeckLink iterator";
125 if (!decklink_iter)
126 return;
127
128 while (decklink_iter->Next(decklink_.Receive()) == S_OK) {
129 CFStringRef device_model_name = NULL;
130 if ((decklink_->GetModelName(&device_model_name) == S_OK) ||
131 (device_name_.id() == base::SysCFStringRefToUTF8(device_model_name))) {
132 break;
133 }
134 decklink_.Release();
135 }
136 if (!decklink_) {
137 SetErrorState("Device id not found in the system");
138 return;
139 }
140
141 if (decklink_->QueryInterface(IID_IDeckLinkInput,
142 decklink_input_.ReceiveVoid()) != S_OK) {
143 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
144 return;
145 }
146
147 ScopedDeckLinkPtr<IDeckLinkDisplayModeIterator> display_mode_iter;
148 if (decklink_input_->GetDisplayModeIterator(display_mode_iter.Receive()) !=
149 S_OK) {
150 SetErrorState("Error creating Display Mode Iterator");
151 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.
152 }
153
154 ScopedDeckLinkPtr<IDeckLinkDisplayMode> chosen_display_mode;
155 ScopedDeckLinkPtr<IDeckLinkDisplayMode> display_mode;
156 int min_diff = INT_MAX;
157 while (display_mode_iter->Next(display_mode.Receive()) == S_OK) {
158 const int diff = abs(display_mode->GetWidth() -
159 params.requested_format.frame_size.width()) +
160 abs(params.requested_format.frame_size.height() -
161 display_mode->GetHeight()) + fabs(params.requested_format.frame_rate -
162 GetDisplayModeFrameRate(display_mode));
163 if (diff < min_diff) {
164 chosen_display_mode = display_mode;
165 min_diff = diff;
166 }
167 display_mode.Release();
168 }
169 if (!chosen_display_mode) {
170 SetErrorState("Could not find a display mode");
171 return;
172 }
173 #if !defined(NDEBUG)
174 CFStringRef format_name = NULL;
175 if (chosen_display_mode->GetName(&format_name) == S_OK)
176 DVLOG(1) << "Chosen format: " << base::SysCFStringRefToUTF8(format_name);
177 #endif
178
179 // Enable video input. Configure for no input video format change detection,
180 // this in turn will disable calls to VideoInputFormatChanged().
181 if (decklink_input_->EnableVideoInput(chosen_display_mode->GetDisplayMode(),
182 bmdFormat8BitYUV, bmdVideoInputFlagDefault) != S_OK) {
183 SetErrorState("Could not select the video format we like.");
184 return;
185 }
186
187 client_ = client.Pass();
188 decklink_input_->SetCallback(this);
189 if (decklink_input_->StartStreams() != S_OK) {
190 SetErrorState("Could not start capturing");
191 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.
192 }
143 } 193 }
144 194
145 void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() { 195 void VideoCaptureDeviceDeckLinkMac::StopAndDeAllocate() {
146 NOTIMPLEMENTED(); 196 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.
197 LogMessage("Problem stopping capture.");
198 decklink_input_->SetCallback(NULL);
199 decklink_input_->DisableVideoInput();
200 }
201
202 HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFormatChanged (
203 BMDVideoInputFormatChangedEvents notification_events,
204 IDeckLinkDisplayMode *new_display_mode,
205 BMDDetectedVideoInputFormatFlags detected_signal_flags) {
206 DVLOG(1) << __FUNCTION__;
tommi (sloooow) - chröme 2014/09/05 09:24:21 thread check?
mcasas 2014/09/09 11:05:00 Done.
207 return S_OK;
208 }
209
210 HRESULT VideoCaptureDeviceDeckLinkMac::VideoInputFrameArrived (
211 IDeckLinkVideoInputFrame* video_frame,
212 IDeckLinkAudioInputPacket* /* audio_packet */) {
213 // 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.
214 void *videoData;
tommi (sloooow) - chröme 2014/09/05 09:24:21 void* video_data = NULL;
mcasas 2014/09/09 11:05:01 Done.
215 video_frame->GetBytes(&videoData);
216
217 VideoPixelFormat pixel_format = PIXEL_FORMAT_UNKNOWN;
218 switch (video_frame->GetPixelFormat()) {
219 case bmdFormat8BitYUV: // A.k.a. '2vuy';
220 pixel_format = PIXEL_FORMAT_UYVY;
221 break;
222 case bmdFormat8BitARGB:
223 pixel_format = PIXEL_FORMAT_ARGB;
224 break;
225 default:
226 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.
227 }
228
229 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
230 gfx::Size(video_frame->GetWidth(), video_frame->GetHeight()),
231 0.0f, // Frame rate is not needed for captured data callback.
232 pixel_format);
233 client_->OnIncomingCapturedData(
234 static_cast<uint8*>(videoData),
235 video_frame->GetRowBytes() * video_frame->GetHeight(),
236 captureFormat,
237 0, // Rotation.
238 base::TimeTicks::Now());
239
240 return S_OK;
241 }
242
243 HRESULT VideoCaptureDeviceDeckLinkMac::QueryInterface(REFIID iid, LPVOID *ppv) {
244 HRESULT result = E_NOINTERFACE;
245 *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.
246 // 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.
247 CFUUIDBytes iunknown = CFUUIDGetUUIDBytes(IUnknownUUID);
248 if (memcmp(&iid, &iunknown, sizeof(REFIID)) == 0) {
249 *ppv = this;
250 AddRef();
251 result = S_OK;
252 } else if (memcmp(&iid, &IID_IDeckLinkNotificationCallback, sizeof(REFIID))
253 == 0) {
254 *ppv = (IDeckLinkNotificationCallback*)this;
tommi (sloooow) - chröme 2014/09/05 09:24:21 static_cast
mcasas 2014/09/09 11:05:00 Acknowledged.
255 AddRef();
256 result = S_OK;
257 }
258 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.
259 }
260
261 ULONG VideoCaptureDeviceDeckLinkMac::AddRef(void) {
262 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
263 }
264
265 ULONG VideoCaptureDeviceDeckLinkMac::Release(void) {
266 int32_t newRefValue = OSAtomicDecrement32(&ref_count_);
267 if (newRefValue == 0) {
268 delete this;
269 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.
270 }
271 return newRefValue;
272 }
273
274
275 void VideoCaptureDeviceDeckLinkMac::SetErrorState(const std::string& reason) {
276 if (client_)
277 client_->OnError(reason);
278 }
279
280 void VideoCaptureDeviceDeckLinkMac::LogMessage(const std::string& message) {
281 if (client_)
282 client_->OnLog(message);
147 } 283 }
148 284
149 } // namespace media 285 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698