| 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 |