| 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(const Name& device_name) { | 213 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { |
| 249 VideoCaptureDevice* ret = NULL; | 214 NOTIMPLEMENTED(); |
| 250 if (device_name.capture_api_type() == Name::MEDIA_FOUNDATION) { | 215 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 } | 216 } |
| 446 | 217 |
| 447 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) | 218 VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name) |
| 448 : device_name_(device_name), | 219 : device_name_(device_name), |
| 449 state_(kIdle) { | 220 state_(kIdle) { |
| 450 DetachFromThread(); | 221 DetachFromThread(); |
| 451 } | 222 } |
| 452 | 223 |
| 453 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { | 224 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { |
| 454 DCHECK(CalledOnValidThread()); | 225 DCHECK(CalledOnValidThread()); |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 789 } | 560 } |
| 790 } | 561 } |
| 791 | 562 |
| 792 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 563 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
| 793 DCHECK(CalledOnValidThread()); | 564 DCHECK(CalledOnValidThread()); |
| 794 DVLOG(1) << reason; | 565 DVLOG(1) << reason; |
| 795 state_ = kError; | 566 state_ = kError; |
| 796 client_->OnError(reason); | 567 client_->OnError(reason); |
| 797 } | 568 } |
| 798 } // namespace media | 569 } // namespace media |
| OLD | NEW |