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