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 <algorithm> | 7 #include <algorithm> |
8 #include <list> | 8 #include <list> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 | 143 |
144 // Delete a media type structure that was allocated on the heap. | 144 // Delete a media type structure that was allocated on the heap. |
145 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx | 145 // http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx |
146 void DeleteMediaType(AM_MEDIA_TYPE* mt) { | 146 void DeleteMediaType(AM_MEDIA_TYPE* mt) { |
147 if (mt != NULL) { | 147 if (mt != NULL) { |
148 FreeMediaType(mt); | 148 FreeMediaType(mt); |
149 CoTaskMemFree(mt); | 149 CoTaskMemFree(mt); |
150 } | 150 } |
151 } | 151 } |
152 | 152 |
153 VideoPixelFormat TranslateMediaSubtypeToPixelFormat(const GUID& sub_type) { | |
154 static struct { | |
155 const GUID& sub_type; | |
156 VideoPixelFormat format; | |
157 } pixel_formats[] = { | |
158 { kMediaSubTypeI420, PIXEL_FORMAT_I420 }, | |
159 { MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420 }, | |
160 { MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24 }, | |
161 { MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2 }, | |
162 { MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG }, | |
163 { MEDIASUBTYPE_UYVY, PIXEL_FORMAT_UYVY }, | |
164 { MEDIASUBTYPE_ARGB32, PIXEL_FORMAT_ARGB }, | |
165 }; | |
166 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(pixel_formats); ++i) { | |
167 if (sub_type == pixel_formats[i].sub_type) | |
168 return pixel_formats[i].format; | |
169 } | |
170 #ifndef NDEBUG | |
171 WCHAR guid_str[128]; | |
172 StringFromGUID2(sub_type, guid_str, arraysize(guid_str)); | |
173 DVLOG(2) << "Device (also) supports an unknown media type " << guid_str; | |
174 #endif | |
175 return PIXEL_FORMAT_UNKNOWN; | |
176 } | |
177 | |
178 } // namespace | 153 } // namespace |
179 | 154 |
180 // static | 155 // static |
181 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { | 156 void VideoCaptureDevice::GetDeviceNames(Names* device_names) { |
182 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 157 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
183 // Use Media Foundation for Metro processes (after and including Win8) and | 158 // Use Media Foundation for Metro processes (after and including Win8) and |
184 // DirectShow for any other versions, unless forced via flag. Media Foundation | 159 // DirectShow for any other versions, unless forced via flag. Media Foundation |
185 // can also be forced if appropriate flag is set and we are in Windows 7 or | 160 // can also be forced if appropriate flag is set and we are in Windows 7 or |
186 // 8 in non-Metro mode. | 161 // 8 in non-Metro mode. |
187 if ((base::win::IsMetroProcess() && | 162 if ((base::win::IsMetroProcess() && |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 | 247 |
273 // Find the description or friendly name. | 248 // Find the description or friendly name. |
274 ScopedVariant name; | 249 ScopedVariant name; |
275 hr = prop_bag->Read(L"Description", name.Receive(), 0); | 250 hr = prop_bag->Read(L"Description", name.Receive(), 0); |
276 if (FAILED(hr)) | 251 if (FAILED(hr)) |
277 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); | 252 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); |
278 | 253 |
279 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { | 254 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { |
280 // Ignore all VFW drivers and the special Google Camera Adapter. | 255 // Ignore all VFW drivers and the special Google Camera Adapter. |
281 // Google Camera Adapter is not a real DirectShow camera device. | 256 // Google Camera Adapter is not a real DirectShow camera device. |
282 // VFW are very old Video for Windows drivers that can not be used. | 257 // VFW is very old Video for Windows drivers that can not be used. |
283 const wchar_t* str_ptr = V_BSTR(&name); | 258 const wchar_t* str_ptr = V_BSTR(&name); |
284 const int name_length = arraysize(kGoogleCameraAdapter) - 1; | 259 const int name_length = arraysize(kGoogleCameraAdapter) - 1; |
285 | 260 |
286 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && | 261 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && |
287 lstrlenW(str_ptr) < name_length || | 262 lstrlenW(str_ptr) < name_length || |
288 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, | 263 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, |
289 kGoogleCameraAdapter)))) { | 264 kGoogleCameraAdapter)))) { |
290 std::string id; | 265 std::string id; |
291 std::string device_name(base::SysWideToUTF8(str_ptr)); | 266 std::string device_name(base::SysWideToUTF8(str_ptr)); |
292 name.Reset(); | 267 name.Reset(); |
293 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); | 268 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); |
294 if (FAILED(hr) || name.type() != VT_BSTR) { | 269 if (FAILED(hr) || name.type() != VT_BSTR) { |
295 id = device_name; | 270 id = device_name; |
296 } else { | 271 } else { |
297 DCHECK_EQ(name.type(), VT_BSTR); | 272 DCHECK_EQ(name.type(), VT_BSTR); |
298 id = base::SysWideToUTF8(V_BSTR(&name)); | 273 id = base::SysWideToUTF8(V_BSTR(&name)); |
299 } | 274 } |
300 | 275 |
301 device_names->push_back(Name(device_name, id, Name::DIRECT_SHOW)); | 276 device_names->push_back(Name(device_name, id, Name::DIRECT_SHOW)); |
302 } | 277 } |
303 } | 278 } |
304 moniker.Release(); | 279 moniker.Release(); |
305 } | 280 } |
306 } | 281 } |
307 | 282 |
308 // static | 283 // static |
309 void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device, | 284 void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device, |
310 VideoCaptureFormats* formats) { | 285 VideoCaptureFormats* formats) { |
311 DVLOG(1) << "GetDeviceSupportedFormats for " << device.name(); | 286 NOTIMPLEMENTED(); |
312 ScopedComPtr<ICreateDevEnum> dev_enum; | |
313 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | |
314 CLSCTX_INPROC); | |
315 if (FAILED(hr)) | |
316 return; | |
317 | |
318 ScopedComPtr<IEnumMoniker> enum_moniker; | |
319 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | |
320 enum_moniker.Receive(), 0); | |
321 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera | |
322 // exists. Therefore the FAILED macro can't be used. | |
323 if (hr != S_OK) | |
324 return; | |
325 | |
326 // Walk the capture devices. No need to check for "google camera adapter", | |
327 // since this is already skipped in the enumeration of GetDeviceNames(). | |
328 ScopedComPtr<IMoniker> moniker; | |
329 int index = 0; | |
330 ScopedVariant device_id; | |
331 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { | |
332 ScopedComPtr<IPropertyBag> prop_bag; | |
333 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | |
334 if (FAILED(hr)) { | |
335 moniker.Release(); | |
336 continue; | |
337 } | |
338 | |
339 device_id.Reset(); | |
340 hr = prop_bag->Read(L"DevicePath", device_id.Receive(), 0); | |
341 if (FAILED(hr)) { | |
342 DVLOG(1) << "Couldn't read a device's DevicePath."; | |
343 return; | |
344 } | |
345 if (device.id() == base::SysWideToUTF8(V_BSTR(&device_id))) | |
346 break; | |
347 moniker.Release(); | |
348 } | |
349 | |
350 if (moniker.get()) { | |
351 base::win::ScopedComPtr<IBaseFilter> capture_filter; | |
352 hr = GetDeviceFilter(device, capture_filter.Receive()); | |
353 if (!capture_filter) { | |
354 DVLOG(2) << "Failed to create capture filter."; | |
355 return; | |
356 } | |
357 | |
358 base::win::ScopedComPtr<IPin> output_capture_pin; | |
359 hr = GetPin(capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, | |
360 output_capture_pin.Receive()); | |
361 if (!output_capture_pin) { | |
362 DVLOG(2) << "Failed to get capture output pin"; | |
363 return; | |
364 } | |
365 | |
366 ScopedComPtr<IAMStreamConfig> stream_config; | |
367 hr = output_capture_pin.QueryInterface(stream_config.Receive()); | |
368 if (FAILED(hr)) { | |
369 DVLOG(2) << "Failed to get IAMStreamConfig interface from " | |
370 "capture device"; | |
371 return; | |
372 } | |
373 | |
374 int count, size; | |
375 hr = stream_config->GetNumberOfCapabilities(&count, &size); | |
376 if (FAILED(hr)) { | |
377 DVLOG(2) << "Failed to GetNumberOfCapabilities"; | |
378 return; | |
379 } | |
380 | |
381 AM_MEDIA_TYPE* media_type = NULL; | |
382 VIDEO_STREAM_CONFIG_CAPS caps; | |
383 for (int i = 0; i < count; ++i) { | |
384 hr = stream_config->GetStreamCaps(i, &media_type, | |
385 reinterpret_cast<BYTE*>(&caps)); | |
386 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | |
387 // macros here since they'll trigger incorrectly. | |
388 if (hr != S_OK) { | |
389 DVLOG(2) << "Failed to GetStreamCaps"; | |
390 return; | |
391 } | |
392 | |
393 if (media_type->majortype == MEDIATYPE_Video && | |
394 media_type->formattype == FORMAT_VideoInfo) { | |
395 VIDEOINFOHEADER* h = | |
396 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | |
397 VideoCaptureFormat format; | |
398 format.frame_size.SetSize(h->bmiHeader.biWidth, | |
399 h->bmiHeader.biHeight); | |
400 // Trust the frame rate from the VIDEOINFOHEADER. | |
401 format.frame_rate = (h->AvgTimePerFrame > 0) ? | |
402 static_cast<int>(kSecondsToReferenceTime / h->AvgTimePerFrame) : | |
403 0; | |
404 format.pixel_format = | |
405 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | |
406 formats->push_back(format); | |
407 DVLOG(1) << device.name() << " resolution: " | |
408 << format.frame_size.ToString() << ", fps: " << format.frame_rate | |
409 << ", pixel format: " << format.pixel_format; | |
410 } | |
411 } | |
412 } | |
413 } | 287 } |
414 | 288 |
415 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) | 289 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) |
416 : device_name_(device_name), | 290 : device_name_(device_name), |
417 state_(kIdle) { | 291 state_(kIdle) { |
418 DetachFromThread(); | 292 DetachFromThread(); |
419 } | 293 } |
420 | 294 |
421 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { | 295 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { |
422 DCHECK(CalledOnValidThread()); | 296 DCHECK(CalledOnValidThread()); |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
701 capability.supported_format.frame_rate = | 575 capability.supported_format.frame_rate = |
702 (time_per_frame > 0) | 576 (time_per_frame > 0) |
703 ? static_cast<int>(kSecondsToReferenceTime / time_per_frame) | 577 ? static_cast<int>(kSecondsToReferenceTime / time_per_frame) |
704 : 0; | 578 : 0; |
705 | 579 |
706 // DirectShow works at the moment only on integer frame_rate but the | 580 // DirectShow works at the moment only on integer frame_rate but the |
707 // best capability matching class works on rational frame rates. | 581 // best capability matching class works on rational frame rates. |
708 capability.frame_rate_numerator = capability.supported_format.frame_rate; | 582 capability.frame_rate_numerator = capability.supported_format.frame_rate; |
709 capability.frame_rate_denominator = 1; | 583 capability.frame_rate_denominator = 1; |
710 | 584 |
711 capability.supported_format.pixel_format = | 585 // We can't switch MEDIATYPE :~(. |
712 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | 586 if (media_type->subtype == kMediaSubTypeI420) { |
| 587 capability.supported_format.pixel_format = PIXEL_FORMAT_I420; |
| 588 } else if (media_type->subtype == MEDIASUBTYPE_IYUV) { |
| 589 // This is identical to PIXEL_FORMAT_I420. |
| 590 capability.supported_format.pixel_format = PIXEL_FORMAT_I420; |
| 591 } else if (media_type->subtype == MEDIASUBTYPE_RGB24) { |
| 592 capability.supported_format.pixel_format = PIXEL_FORMAT_RGB24; |
| 593 } else if (media_type->subtype == MEDIASUBTYPE_YUY2) { |
| 594 capability.supported_format.pixel_format = PIXEL_FORMAT_YUY2; |
| 595 } else if (media_type->subtype == MEDIASUBTYPE_MJPG) { |
| 596 capability.supported_format.pixel_format = PIXEL_FORMAT_MJPEG; |
| 597 } else if (media_type->subtype == MEDIASUBTYPE_UYVY) { |
| 598 capability.supported_format.pixel_format = PIXEL_FORMAT_UYVY; |
| 599 } else if (media_type->subtype == MEDIASUBTYPE_ARGB32) { |
| 600 capability.supported_format.pixel_format = PIXEL_FORMAT_ARGB; |
| 601 } else { |
| 602 WCHAR guid_str[128]; |
| 603 StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str)); |
| 604 DVLOG(2) << "Device supports (also) an unknown media type " << guid_str; |
| 605 continue; |
| 606 } |
713 capabilities_.Add(capability); | 607 capabilities_.Add(capability); |
714 } | 608 } |
715 DeleteMediaType(media_type); | 609 DeleteMediaType(media_type); |
716 media_type = NULL; | 610 media_type = NULL; |
717 } | 611 } |
718 | 612 |
719 return !capabilities_.empty(); | 613 return !capabilities_.empty(); |
720 } | 614 } |
721 | 615 |
722 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 616 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
723 DCHECK(CalledOnValidThread()); | 617 DCHECK(CalledOnValidThread()); |
724 DVLOG(1) << reason; | 618 DVLOG(1) << reason; |
725 state_ = kError; | 619 state_ = kError; |
726 client_->OnError(reason); | 620 client_->OnError(reason); |
727 } | 621 } |
728 } // namespace media | 622 } // namespace media |
OLD | NEW |