OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/win/video_capture_device_win.h" | 5 #include "media/video/capture/win/video_capture_device_win.h" |
6 | 6 |
7 #include <ks.h> | 7 #include <ks.h> |
8 #include <ksmedia.h> | 8 #include <ksmedia.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <list> | 11 #include <list> |
12 | 12 |
13 #include "base/command_line.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
16 #include "base/win/metro.h" | |
17 #include "base/win/scoped_co_mem.h" | 14 #include "base/win/scoped_co_mem.h" |
18 #include "base/win/scoped_variant.h" | 15 #include "base/win/scoped_variant.h" |
19 #include "base/win/windows_version.h" | |
20 #include "media/base/media_switches.h" | |
21 #include "media/video/capture/win/video_capture_device_mf_win.h" | 16 #include "media/video/capture/win/video_capture_device_mf_win.h" |
22 | 17 |
23 using base::win::ScopedCoMem; | 18 using base::win::ScopedCoMem; |
24 using base::win::ScopedComPtr; | |
25 using base::win::ScopedVariant; | 19 using base::win::ScopedVariant; |
26 | 20 |
27 namespace media { | 21 namespace media { |
28 namespace { | |
29 | 22 |
30 // Finds and creates a DirectShow Video Capture filter matching the device_name. | 23 // Finds and creates a DirectShow Video Capture filter matching the device_name. |
31 HRESULT GetDeviceFilter(const VideoCaptureDevice::Name& device_name, | 24 // static |
32 IBaseFilter** filter) { | 25 HRESULT VideoCaptureDeviceWin::GetDeviceFilter( |
26 const VideoCaptureDevice::Name& device_name, | |
27 IBaseFilter** filter) { | |
33 DCHECK(filter); | 28 DCHECK(filter); |
34 | 29 |
35 ScopedComPtr<ICreateDevEnum> dev_enum; | 30 ScopedComPtr<ICreateDevEnum> dev_enum; |
36 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | 31 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
37 CLSCTX_INPROC); | 32 CLSCTX_INPROC); |
38 if (FAILED(hr)) | 33 if (FAILED(hr)) |
39 return hr; | 34 return hr; |
40 | 35 |
41 ScopedComPtr<IEnumMoniker> enum_moniker; | 36 ScopedComPtr<IEnumMoniker> enum_moniker; |
42 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | 37 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 } | 75 } |
81 | 76 |
82 *filter = capture_filter.Detach(); | 77 *filter = capture_filter.Detach(); |
83 if (!*filter && SUCCEEDED(hr)) | 78 if (!*filter && SUCCEEDED(hr)) |
84 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | 79 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); |
85 | 80 |
86 return hr; | 81 return hr; |
87 } | 82 } |
88 | 83 |
89 // Check if a Pin matches a category. | 84 // Check if a Pin matches a category. |
90 bool PinMatchesCategory(IPin* pin, REFGUID category) { | 85 // static |
86 bool VideoCaptureDeviceWin::PinMatchesCategory(IPin* pin, REFGUID category) { | |
91 DCHECK(pin); | 87 DCHECK(pin); |
92 bool found = false; | 88 bool found = false; |
93 ScopedComPtr<IKsPropertySet> ks_property; | 89 ScopedComPtr<IKsPropertySet> ks_property; |
94 HRESULT hr = ks_property.QueryFrom(pin); | 90 HRESULT hr = ks_property.QueryFrom(pin); |
95 if (SUCCEEDED(hr)) { | 91 if (SUCCEEDED(hr)) { |
96 GUID pin_category; | 92 GUID pin_category; |
97 DWORD return_value; | 93 DWORD return_value; |
98 hr = ks_property->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, | 94 hr = ks_property->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, |
99 &pin_category, sizeof(pin_category), &return_value); | 95 &pin_category, sizeof(pin_category), &return_value); |
100 if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) { | 96 if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) { |
101 found = (pin_category == category); | 97 found = (pin_category == category); |
102 } | 98 } |
103 } | 99 } |
104 return found; | 100 return found; |
105 } | 101 } |
106 | 102 |
107 // Finds a IPin on a IBaseFilter given the direction an category. | 103 // Finds a IPin on a IBaseFilter given the direction an category. |
108 ScopedComPtr<IPin> GetPin(IBaseFilter* filter, PIN_DIRECTION pin_dir, | 104 // static |
109 REFGUID category) { | 105 ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter, |
106 PIN_DIRECTION pin_dir, | |
107 REFGUID category) { | |
110 ScopedComPtr<IPin> pin; | 108 ScopedComPtr<IPin> pin; |
111 ScopedComPtr<IEnumPins> pin_emum; | 109 ScopedComPtr<IEnumPins> pin_emum; |
112 HRESULT hr = filter->EnumPins(pin_emum.Receive()); | 110 HRESULT hr = filter->EnumPins(pin_emum.Receive()); |
113 if (pin_emum == NULL) | 111 if (pin_emum == NULL) |
114 return pin; | 112 return pin; |
115 | 113 |
116 // Get first unconnected pin. | 114 // Get first unconnected pin. |
117 hr = pin_emum->Reset(); // set to first pin | 115 hr = pin_emum->Reset(); // set to first pin |
118 while ((hr = pin_emum->Next(1, pin.Receive(), NULL)) == S_OK) { | 116 while ((hr = pin_emum->Next(1, pin.Receive(), NULL)) == S_OK) { |
119 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1); | 117 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1); |
120 hr = pin->QueryDirection(&this_pin_dir); | 118 hr = pin->QueryDirection(&this_pin_dir); |
121 if (pin_dir == this_pin_dir) { | 119 if (pin_dir == this_pin_dir) { |
122 if (category == GUID_NULL || PinMatchesCategory(pin, category)) | 120 if (category == GUID_NULL || PinMatchesCategory(pin, category)) |
123 return pin; | 121 return pin; |
124 } | 122 } |
125 pin.Release(); | 123 pin.Release(); |
126 } | 124 } |
127 | 125 |
128 DCHECK(!pin); | 126 DCHECK(!pin); |
129 return pin; | 127 return pin; |
130 } | 128 } |
131 | 129 |
132 // Release the format block for a media type. | 130 // static |
133 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx | 131 VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat( |
134 void FreeMediaType(AM_MEDIA_TYPE* mt) { | 132 const GUID& sub_type) { |
135 if (mt->cbFormat != 0) { | |
136 CoTaskMemFree(mt->pbFormat); | |
137 mt->cbFormat = 0; | |
138 mt->pbFormat = NULL; | |
139 } | |
140 if (mt->pUnk != NULL) { | |
141 NOTREACHED(); | |
142 // pUnk should not be used. | |
143 mt->pUnk->Release(); | |
144 mt->pUnk = NULL; | |
145 } | |
146 } | |
147 | |
148 // Delete a media type structure that was allocated on the heap. | |
149 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx | |
150 void DeleteMediaType(AM_MEDIA_TYPE* mt) { | |
151 if (mt != NULL) { | |
152 FreeMediaType(mt); | |
153 CoTaskMemFree(mt); | |
154 } | |
155 } | |
156 | |
157 // A utility class that wraps the AM_MEDIA_TYPE type and guarantees that | |
158 // we free the structure when exiting the scope. DCHECKing is also done to | |
159 // avoid memory leaks. | |
160 class ScopedMediaType { | |
161 public: | |
162 ScopedMediaType() : media_type_(NULL) {} | |
163 ~ScopedMediaType() { Free(); } | |
164 | |
165 AM_MEDIA_TYPE* operator->() { return media_type_; } | |
166 AM_MEDIA_TYPE* get() { return media_type_; } | |
167 | |
168 void Free() { | |
169 if (!media_type_) | |
170 return; | |
171 | |
172 DeleteMediaType(media_type_); | |
173 media_type_= NULL; | |
174 } | |
175 | |
176 AM_MEDIA_TYPE** Receive() { | |
177 DCHECK(!media_type_); | |
178 return &media_type_; | |
179 } | |
180 | |
181 private: | |
182 AM_MEDIA_TYPE* media_type_; | |
183 }; | |
184 | |
185 VideoPixelFormat TranslateMediaSubtypeToPixelFormat(const GUID& sub_type) { | |
186 static struct { | 133 static struct { |
187 const GUID& sub_type; | 134 const GUID& sub_type; |
188 VideoPixelFormat format; | 135 VideoPixelFormat format; |
189 } pixel_formats[] = { | 136 } pixel_formats[] = { |
190 { kMediaSubTypeI420, PIXEL_FORMAT_I420 }, | 137 { kMediaSubTypeI420, PIXEL_FORMAT_I420 }, |
191 { MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420 }, | 138 { MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420 }, |
192 { MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24 }, | 139 { MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24 }, |
193 { MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2 }, | 140 { MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2 }, |
194 { MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG }, | 141 { MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG }, |
195 { MEDIASUBTYPE_UYVY, PIXEL_FORMAT_UYVY }, | 142 { MEDIASUBTYPE_UYVY, PIXEL_FORMAT_UYVY }, |
196 { MEDIASUBTYPE_ARGB32, PIXEL_FORMAT_ARGB }, | 143 { MEDIASUBTYPE_ARGB32, PIXEL_FORMAT_ARGB }, |
197 }; | 144 }; |
198 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(pixel_formats); ++i) { | 145 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(pixel_formats); ++i) { |
199 if (sub_type == pixel_formats[i].sub_type) | 146 if (sub_type == pixel_formats[i].sub_type) |
200 return pixel_formats[i].format; | 147 return pixel_formats[i].format; |
201 } | 148 } |
202 #ifndef NDEBUG | 149 #ifndef NDEBUG |
203 WCHAR guid_str[128]; | 150 WCHAR guid_str[128]; |
204 StringFromGUID2(sub_type, guid_str, arraysize(guid_str)); | 151 StringFromGUID2(sub_type, guid_str, arraysize(guid_str)); |
205 DVLOG(2) << "Device (also) supports an unknown media type " << guid_str; | 152 DVLOG(2) << "Device (also) supports an unknown media type " << guid_str; |
206 #endif | 153 #endif |
207 return PIXEL_FORMAT_UNKNOWN; | 154 return PIXEL_FORMAT_UNKNOWN; |
208 } | 155 } |
209 | 156 |
210 } // namespace | 157 void VideoCaptureDeviceWin::ScopedMediaType::Free() { |
158 if (!media_type_) | |
159 return; | |
160 | |
161 DeleteMediaType(media_type_); | |
162 media_type_= NULL; | |
163 } | |
164 | |
165 AM_MEDIA_TYPE** VideoCaptureDeviceWin::ScopedMediaType::Receive() { | |
166 DCHECK(!media_type_); | |
167 return &media_type_; | |
168 } | |
169 | |
170 // Release the format block for a media type. | |
171 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx | |
172 void VideoCaptureDeviceWin::ScopedMediaType::FreeMediaType(AM_MEDIA_TYPE* mt) { | |
173 if (mt->cbFormat != 0) { | |
174 CoTaskMemFree(mt->pbFormat); | |
175 mt->cbFormat = 0; | |
176 mt->pbFormat = NULL; | |
177 } | |
178 if (mt->pUnk != NULL) { | |
179 NOTREACHED(); | |
180 // pUnk should not be used. | |
181 mt->pUnk->Release(); | |
182 mt->pUnk = NULL; | |
183 } | |
184 } | |
185 | |
186 // Delete a media type structure that was allocated on the heap. | |
187 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx | |
188 void VideoCaptureDeviceWin::ScopedMediaType::DeleteMediaType( | |
189 AM_MEDIA_TYPE* mt) { | |
190 if (mt != NULL) { | |
191 FreeMediaType(mt); | |
192 CoTaskMemFree(mt); | |
193 } | |
194 } | |
211 | 195 |
212 // static | 196 // static |
213 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { | 197 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
214 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 198 NOTIMPLEMENTED(); |
tommi (sloooow) - chröme
2014/05/15 15:18:33
not implemented? am I perhaps looking at a strang
mcasas
2014/05/15 16:03:23
It's missing a comment (like in Mac/Linux/Win).
V
tommi (sloooow) - chröme
2014/05/19 10:51:37
Can we #ifdef this so that it's clear on what plat
mcasas
2014/05/19 12:59:50
Discussed offline.
| |
215 // Use Media Foundation for Metro processes (after and including Win8) and | |
216 // DirectShow for any other versions, unless forced via flag. Media Foundation | |
217 // can also be forced if appropriate flag is set and we are in Windows 7 or | |
218 // 8 in non-Metro mode. | |
219 if ((base::win::IsMetroProcess() && | |
220 !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) || | |
221 (base::win::GetVersion() >= base::win::VERSION_WIN7 && | |
222 cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture))) { | |
223 VideoCaptureDeviceMFWin::GetDeviceNames(device_names); | |
224 } else { | |
225 VideoCaptureDeviceWin::GetDeviceNames(device_names); | |
226 } | |
227 } | 199 } |
228 | 200 |
229 // static | 201 // static |
230 void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device, | 202 void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device, |
231 VideoCaptureFormats* formats) { | 203 VideoCaptureFormats* formats) { |
232 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 204 NOTIMPLEMENTED(); |
tommi (sloooow) - chröme
2014/05/15 15:18:33
same here... I'm a bit confused (same for Create b
mcasas
2014/05/15 16:03:23
Done.
| |
233 // Use Media Foundation for Metro processes (after and including Win8) and | |
234 // DirectShow for any other versions, unless forced via flag. Media Foundation | |
235 // can also be forced if appropriate flag is set and we are in Windows 7 or | |
236 // 8 in non-Metro mode. | |
237 if ((base::win::IsMetroProcess() && | |
238 !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) || | |
239 (base::win::GetVersion() >= base::win::VERSION_WIN7 && | |
240 cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture))) { | |
241 VideoCaptureDeviceMFWin::GetDeviceSupportedFormats(device, formats); | |
242 } else { | |
243 VideoCaptureDeviceWin::GetDeviceSupportedFormats(device, formats); | |
244 } | |
245 } | 205 } |
246 | 206 |
247 // static | 207 // static |
248 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { | 208 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
249 VideoCaptureDevice* ret = NULL; | 209 NOTIMPLEMENTED(); |
250 if (device_name.capture_api_type() == Name::MEDIA_FOUNDATION) { | 210 return NULL; |
251 DCHECK(VideoCaptureDeviceMFWin::PlatformSupported()); | |
252 scoped_ptr<VideoCaptureDeviceMFWin> device( | |
253 new VideoCaptureDeviceMFWin(device_name)); | |
254 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); | |
255 if (device->Init()) | |
256 ret = device.release(); | |
257 } else if (device_name.capture_api_type() == Name::DIRECT_SHOW) { | |
258 scoped_ptr<VideoCaptureDeviceWin> device( | |
259 new VideoCaptureDeviceWin(device_name)); | |
260 DVLOG(1) << " DirectShow Device: " << device_name.name(); | |
261 if (device->Init()) | |
262 ret = device.release(); | |
263 } else{ | |
264 NOTREACHED() << " Couldn't recognize VideoCaptureDevice type"; | |
265 } | |
266 | |
267 return ret; | |
268 } | |
269 | |
270 // static | |
271 void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { | |
272 DCHECK(device_names); | |
273 | |
274 ScopedComPtr<ICreateDevEnum> dev_enum; | |
275 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | |
276 CLSCTX_INPROC); | |
277 if (FAILED(hr)) | |
278 return; | |
279 | |
280 ScopedComPtr<IEnumMoniker> enum_moniker; | |
281 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | |
282 enum_moniker.Receive(), 0); | |
283 // CreateClassEnumerator returns S_FALSE on some Windows OS | |
284 // when no camera exist. Therefore the FAILED macro can't be used. | |
285 if (hr != S_OK) | |
286 return; | |
287 | |
288 device_names->clear(); | |
289 | |
290 // Name of a fake DirectShow filter that exist on computers with | |
291 // GTalk installed. | |
292 static const char kGoogleCameraAdapter[] = "google camera adapter"; | |
293 | |
294 // Enumerate all video capture devices. | |
295 ScopedComPtr<IMoniker> moniker; | |
296 int index = 0; | |
297 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { | |
298 ScopedComPtr<IPropertyBag> prop_bag; | |
299 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | |
300 if (FAILED(hr)) { | |
301 moniker.Release(); | |
302 continue; | |
303 } | |
304 | |
305 // Find the description or friendly name. | |
306 ScopedVariant name; | |
307 hr = prop_bag->Read(L"Description", name.Receive(), 0); | |
308 if (FAILED(hr)) | |
309 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); | |
310 | |
311 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { | |
312 // Ignore all VFW drivers and the special Google Camera Adapter. | |
313 // Google Camera Adapter is not a real DirectShow camera device. | |
314 // VFW are very old Video for Windows drivers that can not be used. | |
315 const wchar_t* str_ptr = V_BSTR(&name); | |
316 const int name_length = arraysize(kGoogleCameraAdapter) - 1; | |
317 | |
318 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && | |
319 lstrlenW(str_ptr) < name_length || | |
320 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, | |
321 kGoogleCameraAdapter)))) { | |
322 std::string id; | |
323 std::string device_name(base::SysWideToUTF8(str_ptr)); | |
324 name.Reset(); | |
325 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); | |
326 if (FAILED(hr) || name.type() != VT_BSTR) { | |
327 id = device_name; | |
328 } else { | |
329 DCHECK_EQ(name.type(), VT_BSTR); | |
330 id = base::SysWideToUTF8(V_BSTR(&name)); | |
331 } | |
332 | |
333 device_names->push_back(Name(device_name, id, Name::DIRECT_SHOW)); | |
334 } | |
335 } | |
336 moniker.Release(); | |
337 } | |
338 } | |
339 | |
340 // static | |
341 void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device, | |
342 VideoCaptureFormats* formats) { | |
343 DVLOG(1) << "GetDeviceSupportedFormats for " << device.name(); | |
344 ScopedComPtr<ICreateDevEnum> dev_enum; | |
345 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | |
346 CLSCTX_INPROC); | |
347 if (FAILED(hr)) | |
348 return; | |
349 | |
350 ScopedComPtr<IEnumMoniker> enum_moniker; | |
351 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | |
352 enum_moniker.Receive(), 0); | |
353 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera | |
354 // exists. Therefore the FAILED macro can't be used. | |
355 if (hr != S_OK) | |
356 return; | |
357 | |
358 // Walk the capture devices. No need to check for "google camera adapter", | |
359 // since this is already skipped in the enumeration of GetDeviceNames(). | |
360 ScopedComPtr<IMoniker> moniker; | |
361 int index = 0; | |
362 ScopedVariant device_id; | |
363 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { | |
364 ScopedComPtr<IPropertyBag> prop_bag; | |
365 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | |
366 if (FAILED(hr)) { | |
367 moniker.Release(); | |
368 continue; | |
369 } | |
370 | |
371 device_id.Reset(); | |
372 hr = prop_bag->Read(L"DevicePath", device_id.Receive(), 0); | |
373 if (FAILED(hr)) { | |
374 DVLOG(1) << "Couldn't read a device's DevicePath."; | |
375 return; | |
376 } | |
377 if (device.id() == base::SysWideToUTF8(V_BSTR(&device_id))) | |
378 break; | |
379 moniker.Release(); | |
380 } | |
381 | |
382 if (moniker.get()) { | |
383 base::win::ScopedComPtr<IBaseFilter> capture_filter; | |
384 hr = GetDeviceFilter(device, capture_filter.Receive()); | |
385 if (!capture_filter) { | |
386 DVLOG(2) << "Failed to create capture filter."; | |
387 return; | |
388 } | |
389 | |
390 base::win::ScopedComPtr<IPin> output_capture_pin( | |
391 GetPin(capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE)); | |
392 if (!output_capture_pin) { | |
393 DVLOG(2) << "Failed to get capture output pin"; | |
394 return; | |
395 } | |
396 | |
397 ScopedComPtr<IAMStreamConfig> stream_config; | |
398 hr = output_capture_pin.QueryInterface(stream_config.Receive()); | |
399 if (FAILED(hr)) { | |
400 DVLOG(2) << "Failed to get IAMStreamConfig interface from " | |
401 "capture device"; | |
402 return; | |
403 } | |
404 | |
405 int count = 0, size = 0; | |
406 hr = stream_config->GetNumberOfCapabilities(&count, &size); | |
407 if (FAILED(hr)) { | |
408 DVLOG(2) << "Failed to GetNumberOfCapabilities"; | |
409 return; | |
410 } | |
411 | |
412 scoped_ptr<BYTE[]> caps(new BYTE[size]); | |
413 for (int i = 0; i < count; ++i) { | |
414 ScopedMediaType media_type; | |
415 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); | |
416 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | |
417 // macros here since they'll trigger incorrectly. | |
418 if (hr != S_OK) { | |
419 DVLOG(2) << "Failed to GetStreamCaps"; | |
420 return; | |
421 } | |
422 | |
423 if (media_type->majortype == MEDIATYPE_Video && | |
424 media_type->formattype == FORMAT_VideoInfo) { | |
425 VideoCaptureFormat format; | |
426 format.pixel_format = | |
427 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | |
428 if (format.pixel_format == PIXEL_FORMAT_UNKNOWN) | |
429 continue; | |
430 VIDEOINFOHEADER* h = | |
431 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | |
432 format.frame_size.SetSize(h->bmiHeader.biWidth, | |
433 h->bmiHeader.biHeight); | |
434 // Trust the frame rate from the VIDEOINFOHEADER. | |
435 format.frame_rate = (h->AvgTimePerFrame > 0) ? | |
436 static_cast<int>(kSecondsToReferenceTime / h->AvgTimePerFrame) : | |
437 0; | |
438 formats->push_back(format); | |
439 DVLOG(1) << device.name() << " resolution: " | |
440 << format.frame_size.ToString() << ", fps: " << format.frame_rate | |
441 << ", pixel format: " << format.pixel_format; | |
442 } | |
443 } | |
444 } | |
445 } | 211 } |
446 | 212 |
447 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) | 213 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) |
448 : device_name_(device_name), | 214 : device_name_(device_name), |
449 state_(kIdle) { | 215 state_(kIdle) { |
450 DetachFromThread(); | 216 DetachFromThread(); |
451 } | 217 } |
452 | 218 |
453 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { | 219 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { |
454 DCHECK(CalledOnValidThread()); | 220 DCHECK(CalledOnValidThread()); |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
789 } | 555 } |
790 } | 556 } |
791 | 557 |
792 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 558 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
793 DCHECK(CalledOnValidThread()); | 559 DCHECK(CalledOnValidThread()); |
794 DVLOG(1) << reason; | 560 DVLOG(1) << reason; |
795 state_ = kError; | 561 state_ = kError; |
796 client_->OnError(reason); | 562 client_->OnError(reason); |
797 } | 563 } |
798 } // namespace media | 564 } // namespace media |
OLD | NEW |