Index: media/video/capture/win/video_capture_device_win.cc |
diff --git a/media/video/capture/win/video_capture_device_win.cc b/media/video/capture/win/video_capture_device_win.cc |
index c0bd9d27ca51880574fb7a6158932c7c7d873f1f..1dd96d9b9a66eef60cd41adab61f57d70c5d3527 100644 |
--- a/media/video/capture/win/video_capture_device_win.cc |
+++ b/media/video/capture/win/video_capture_device_win.cc |
@@ -150,6 +150,31 @@ void DeleteMediaType(AM_MEDIA_TYPE* mt) { |
} |
} |
+VideoPixelFormat TranslateMediaSubtypeToPixelFormat(GUID subtype) { |
tommi (sloooow) - chröme
2014/02/17 12:58:29
sub_type? Also, pass by const&?
mcasas
2014/02/17 14:56:20
Done.
|
+ // We can't use a GUID in a switch-case, this applies to |subtype|. |
+ if (subtype == kMediaSubTypeI420) { |
tommi (sloooow) - chröme
2014/02/17 12:58:29
I would like to see this data driven instead of mu
mcasas
2014/02/17 14:56:20
Done.
|
+ return PIXEL_FORMAT_I420; |
+ } else if (subtype == MEDIASUBTYPE_IYUV) { |
+ // This is identical to PIXEL_FORMAT_I420. |
+ return PIXEL_FORMAT_I420; |
+ } else if (subtype == MEDIASUBTYPE_RGB24) { |
+ return PIXEL_FORMAT_RGB24; |
+ } else if (subtype == MEDIASUBTYPE_YUY2) { |
+ return PIXEL_FORMAT_YUY2; |
+ } else if (subtype == MEDIASUBTYPE_MJPG) { |
+ return PIXEL_FORMAT_MJPEG; |
+ } else if (subtype == MEDIASUBTYPE_UYVY) { |
+ return PIXEL_FORMAT_UYVY; |
+ } else if (subtype == MEDIASUBTYPE_ARGB32) { |
+ return PIXEL_FORMAT_ARGB; |
+ } else { |
+ WCHAR guid_str[128]; |
+ StringFromGUID2(subtype, guid_str, arraysize(guid_str)); |
tommi (sloooow) - chröme
2014/02/17 12:58:29
(I know this is just moved code)
This should be in
mcasas
2014/02/17 14:56:20
Done.
|
+ DVLOG(2) << "Device supports (also) an unknown media type " << guid_str; |
+ return PIXEL_FORMAT_UNKNOWN; |
+ } |
+} |
+ |
} // namespace |
// static |
@@ -254,7 +279,7 @@ void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { |
if (SUCCEEDED(hr) && name.type() == VT_BSTR) { |
// Ignore all VFW drivers and the special Google Camera Adapter. |
// Google Camera Adapter is not a real DirectShow camera device. |
- // VFW is very old Video for Windows drivers that can not be used. |
+ // VFW are very old Video for Windows drivers that can not be used. |
const wchar_t* str_ptr = V_BSTR(&name); |
const int name_length = arraysize(kGoogleCameraAdapter) - 1; |
@@ -283,7 +308,107 @@ void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) { |
// static |
void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device, |
VideoCaptureFormats* formats) { |
- NOTIMPLEMENTED(); |
+ DVLOG(1) << "GetDeviceSupportedFormats for " << device.name(); |
+ ScopedComPtr<ICreateDevEnum> dev_enum; |
+ HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
+ CLSCTX_INPROC); |
+ if (FAILED(hr)) |
+ return; |
+ |
+ ScopedComPtr<IEnumMoniker> enum_moniker; |
+ hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, |
+ enum_moniker.Receive(), 0); |
+ // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera |
+ // exists. Therefore the FAILED macro can't be used. |
+ if (hr != S_OK) |
+ return; |
+ |
+ // Walk the capture devices. No need to check for "google camera adapter". |
tommi (sloooow) - chröme
2014/02/17 12:58:29
maybe elaborate on why not?
mcasas
2014/02/17 14:56:20
Done.
|
+ ScopedComPtr<IMoniker> moniker; |
+ int index = 0; |
+ ScopedVariant device_id; |
+ while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { |
+ ScopedComPtr<IPropertyBag> prop_bag; |
+ hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); |
+ if (FAILED(hr)) { |
+ moniker.Release(); |
+ continue; |
+ } |
+ |
+ device_id.Reset(); |
+ hr = prop_bag->Read(L"DevicePath", device_id.Receive(), 0); |
+ if (FAILED(hr)) { |
+ DVLOG(1) << "Couldn't read a device's DevicePath."; |
+ return; |
+ } |
+ if (device.id() == base::SysWideToUTF8(V_BSTR(&device_id))) |
+ break; |
+ moniker.Release(); |
+ } |
+ |
+ if (moniker.get()) { |
+ base::win::ScopedComPtr<IBaseFilter> capture_filter; |
+ hr = GetDeviceFilter(device, capture_filter.Receive()); |
+ if (!capture_filter) { |
+ DVLOG(2) << "Failed to create capture filter."; |
+ return; |
+ } |
+ |
+ base::win::ScopedComPtr<IPin> output_capture_pin; |
+ hr = GetPin(capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, |
+ output_capture_pin.Receive()); |
+ if (!output_capture_pin) { |
+ DVLOG(2) << "Failed to get capture output pin"; |
+ return; |
+ } |
+ |
+ ScopedComPtr<IAMStreamConfig> stream_config; |
+ hr = output_capture_pin.QueryInterface(stream_config.Receive()); |
+ if (FAILED(hr)) { |
+ DVLOG(2) << "Failed to get IAMStreamConfig interface from " |
+ "capture device"; |
+ return; |
+ } |
+ |
+ int count, size; |
+ hr = stream_config->GetNumberOfCapabilities(&count, &size); |
+ if (FAILED(hr)) { |
+ DVLOG(2) << "Failed to GetNumberOfCapabilities"; |
+ return; |
+ } |
+ |
+ AM_MEDIA_TYPE* media_type = NULL; |
+ VIDEO_STREAM_CONFIG_CAPS caps; |
+ for (int i = 0; i < count; ++i) { |
+ hr = stream_config->GetStreamCaps(i, &media_type, |
+ reinterpret_cast<BYTE*>(&caps)); |
+ // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() |
+ // macros here since they'll trigger incorrectly. |
+ if (hr != S_OK) { |
+ DVLOG(2) << "Failed to GetStreamCaps"; |
+ return; |
+ } |
+ |
+ if (media_type->majortype == MEDIATYPE_Video && |
+ media_type->formattype == FORMAT_VideoInfo) { |
+ VIDEOINFOHEADER* h = |
+ reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
+ VideoCaptureFormat format; |
+ format.frame_size.SetSize(h->bmiHeader.biWidth, |
+ h->bmiHeader.biHeight); |
+ // Trust the frame rate from the VIDEOINFOHEADER. |
+ format.frame_rate = (h->AvgTimePerFrame > 0) |
+ ? static_cast<int>(kSecondsToReferenceTime / h->AvgTimePerFrame) |
tommi (sloooow) - chröme
2014/02/17 12:58:29
nit: I think the convention is to have the operato
mcasas
2014/02/17 14:56:20
Done.
|
+ : 0; |
+ format.pixel_format = |
+ TranslateMediaSubtypeToPixelFormat(media_type->subtype); |
+ formats->push_back(format); |
+ DVLOG(1) << device.name() << " resolution: " |
+ << format.frame_size.ToString() << ", fps: " << format.frame_rate |
+ << ", pixel format: " << format.pixel_format; |
+ } |
+ } |
+ } |
} |
VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) |
@@ -582,28 +707,8 @@ bool VideoCaptureDeviceWin::CreateCapabilityMap() { |
capability.frame_rate_numerator = capability.supported_format.frame_rate; |
capability.frame_rate_denominator = 1; |
- // We can't switch MEDIATYPE :~(. |
- if (media_type->subtype == kMediaSubTypeI420) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_I420; |
- } else if (media_type->subtype == MEDIASUBTYPE_IYUV) { |
- // This is identical to PIXEL_FORMAT_I420. |
- capability.supported_format.pixel_format = PIXEL_FORMAT_I420; |
- } else if (media_type->subtype == MEDIASUBTYPE_RGB24) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_RGB24; |
- } else if (media_type->subtype == MEDIASUBTYPE_YUY2) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_YUY2; |
- } else if (media_type->subtype == MEDIASUBTYPE_MJPG) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_MJPEG; |
- } else if (media_type->subtype == MEDIASUBTYPE_UYVY) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_UYVY; |
- } else if (media_type->subtype == MEDIASUBTYPE_ARGB32) { |
- capability.supported_format.pixel_format = PIXEL_FORMAT_ARGB; |
- } else { |
- WCHAR guid_str[128]; |
- StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str)); |
- DVLOG(2) << "Device supports (also) an unknown media type " << guid_str; |
- continue; |
- } |
+ capability.supported_format.pixel_format = |
+ TranslateMediaSubtypeToPixelFormat(media_type->subtype); |
capabilities_.Add(capability); |
} |
DeleteMediaType(media_type); |