1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org/*
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  Use of this source code is governed by a BSD-style license
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  that can be found in the LICENSE file in the root of the source
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  tree. An additional intellectual property rights grant can be found
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  in the file PATENTS.  All contributing project authors may
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1187c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/modules/video_capture/windows/device_info_ds.h"
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1387c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/modules/video_capture/video_capture_config.h"
1487c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/modules/video_capture/video_capture_delay.h"
1587c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/modules/video_capture/windows/help_functions_ds.h"
1687c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/system_wrappers/interface/ref_count.h"
1787c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include "webrtc/system_wrappers/interface/trace.h"
18b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
19b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org#include <Dvdmedia.h>
2087c29b570711208c5f74bf9eaffbea549de866c7pbos@webrtc.org#include <Streams.h>
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace webrtc
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.orgnamespace videocapturemodule
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
26f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgconst int32_t NoWindowsCaptureDelays = 1;
270f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.orgconst DelayValues WindowsCaptureDelays[NoWindowsCaptureDelays] = {
280f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org  "Microsoft LifeCam Cinema",
290f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org  "usb#vid_045e&pid_075d",
300f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org  {
310f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {640,480,125},
320f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {640,360,117},
330f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {424,240,111},
340f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {352,288,111},
350f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {320,240,116},
360f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {176,144,101},
370f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {160,120,109},
380f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {1280,720,166},
390f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {960,544,126},
400f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {800,448,120},
410f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    {800,600,127}
420f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org  },
430f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org};
440f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org
450f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org// static
46f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgDeviceInfoDS* DeviceInfoDS::Create(const int32_t id)
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
480f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    DeviceInfoDS* dsInfo = new DeviceInfoDS(id);
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!dsInfo || dsInfo->Init() != 0)
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        delete dsInfo;
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        dsInfo = NULL;
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return dsInfo;
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
57f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgDeviceInfoDS::DeviceInfoDS(const int32_t id)
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    : DeviceInfoImpl(id), _dsDevEnum(NULL), _dsMonikerDevEnum(NULL),
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      _CoUninitializeIsRequired(true)
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // 1) Initialize the COM library (make Windows load the DLLs).
62b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // CoInitializeEx must be called at least once, and is usually called only once,
64b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // for each thread that uses the COM library. Multiple calls to CoInitializeEx
65b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // by the same thread are allowed as long as they pass the same concurrency flag,
66b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // but subsequent valid calls return S_FALSE.
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // To close the COM library gracefully on a thread, each successful call to
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // CoInitializeEx, including any call that returns S_FALSE, must be balanced
69b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // by a corresponding call to CoUninitialize.
70b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    //
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    /*Apartment-threading, while allowing for multiple threads of execution,
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     serializes all incoming calls by requiring that calls to methods of objects created by this thread always run on the same thread
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     the apartment/thread that created them. In addition, calls can arrive only at message-queue boundaries (i.e., only during a
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     PeekMessage, SendMessage, DispatchMessage, etc.). Because of this serialization, it is not typically necessary to write concurrency control into
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     the code for the object, other than to avoid calls to PeekMessage and SendMessage during processing that must not be interrupted by other method
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org     invocations or calls to other objects in the same apartment/thread.*/
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
79d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org    ///CoInitializeEx(NULL, COINIT_APARTMENTTHREADED ); //| COINIT_SPEED_OVER_MEMORY
80b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // Use COINIT_MULTITHREADED since Voice Engine uses COINIT_MULTITHREADED
81b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (FAILED(hr))
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
83b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        // Avoid calling CoUninitialize() since CoInitializeEx() failed.
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _CoUninitializeIsRequired = FALSE;
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
86b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (hr == RPC_E_CHANGED_MODE)
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Calling thread has already initialized COM to be used in a single-threaded
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // apartment (STA). We are then prevented from using STA.
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Details: hr = 0x80010106 <=> "Cannot change thread mode after it is set".
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            //
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "VideoCaptureWindowsDSInfo::VideoCaptureWindowsDSInfo "
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) => "
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "RPC_E_CHANGED_MODE, error 0x%x",
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         hr);
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
1010f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.orgDeviceInfoDS::~DeviceInfoDS()
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
103b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(_dsMonikerDevEnum);
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(_dsDevEnum);
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (_CoUninitializeIsRequired)
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CoUninitialize();
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
111f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::Init()
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                  IID_ICreateDevEnum, (void **) &_dsDevEnum);
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hr != NOERROR)
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to create CLSID_SystemDeviceEnum, error 0x%x", hr);
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
121b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
122b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
123f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orguint32_t DeviceInfoDS::NumberOfDevices()
124b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
125b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ReadLockScoped cs(_apiLock);
126b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0);
1273b7f2ab86f3d03989abdaff7091f83cddaf26aedtommi@webrtc.org}
1280f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org
129f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::GetDeviceName(
130f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceNumber,
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* deviceNameUTF8,
132f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceNameLength,
133b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* deviceUniqueIdUTF8,
134f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceUniqueIdUTF8Length,
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* productUniqueIdUTF8,
136f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t productUniqueIdUTF8Length)
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
138b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ReadLockScoped cs(_apiLock);
139f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    const int32_t result = GetDeviceInfo(deviceNumber, deviceNameUTF8,
140f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         deviceNameLength,
141f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         deviceUniqueIdUTF8,
142f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         deviceUniqueIdUTF8Length,
143f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         productUniqueIdUTF8,
144f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         productUniqueIdUTF8Length);
145f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    return result > (int32_t) deviceNumber ? 0 : -1;
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
148f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::GetDeviceInfo(
149f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceNumber,
150b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* deviceNameUTF8,
151f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceNameLength,
152b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* deviceUniqueIdUTF8,
153f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t deviceUniqueIdUTF8Length,
154b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                       char* productUniqueIdUTF8,
155f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                       uint32_t productUniqueIdUTF8Length)
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // enumerate all video capture devices
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(_dsMonikerDevEnum);
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr =
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                          &_dsMonikerDevEnum, 0);
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hr != NOERROR)
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to enumerate CLSID_SystemDeviceEnum, error 0x%x."
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " No webcam exist?", hr);
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
172b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dsMonikerDevEnum->Reset();
173b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ULONG cFetched;
174b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IMoniker *pM;
175b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int index = 0;
176b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched))
177b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        IPropertyBag *pBag;
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **) &pBag);
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (S_OK == hr)
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Find the description or friendly name.
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VARIANT varName;
184b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VariantInit(&varName);
185b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            hr = pBag->Read(L"Description", &varName, 0);
186b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (FAILED(hr))
187b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
188b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                hr = pBag->Read(L"FriendlyName", &varName, 0);
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (SUCCEEDED(hr))
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
192b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // ignore all VFW drivers
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if ((wcsstr(varName.bstrVal, (L"(VFW)")) == NULL) &&
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    (_wcsnicmp(varName.bstrVal, (L"Google Camera Adapter"),21)
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        != 0))
196b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
197d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org                    // Found a valid device.
198d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org                    if (index == static_cast<int>(deviceNumber))
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        int convResult = 0;
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        if (deviceNameLength > 0)
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        {
203b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            convResult = WideCharToMultiByte(CP_UTF8, 0,
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                             varName.bstrVal, -1,
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                             (char*) deviceNameUTF8,
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                             deviceNameLength, NULL,
207b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                             NULL);
208b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            if (convResult == 0)
209b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            {
210b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                WEBRTC_TRACE(webrtc::kTraceError,
211b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             webrtc::kTraceVideoCapture, _id,
212b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             "Failed to convert device name to UTF8. %d",
213b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             GetLastError());
214b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                return -1;
215b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            }
216b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        }
217b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        if (deviceUniqueIdUTF8Length > 0)
218b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        {
219b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            hr = pBag->Read(L"DevicePath", &varName, 0);
220b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            if (FAILED(hr))
221b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            {
222b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                strncpy_s((char *) deviceUniqueIdUTF8,
223b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                          deviceUniqueIdUTF8Length,
224b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                          (char *) deviceNameUTF8, convResult);
225b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                WEBRTC_TRACE(webrtc::kTraceError,
226b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             webrtc::kTraceVideoCapture, _id,
227b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                             "Failed to get deviceUniqueIdUTF8 using deviceNameUTF8");
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            }
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            else
230b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            {
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                convResult = WideCharToMultiByte(
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          CP_UTF8,
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          0,
234b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          varName.bstrVal,
235b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          -1,
236b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          (char*) deviceUniqueIdUTF8,
237b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          deviceUniqueIdUTF8Length,
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                          NULL, NULL);
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                if (convResult == 0)
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                {
241b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    WEBRTC_TRACE(webrtc::kTraceError,
242b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 webrtc::kTraceVideoCapture, _id,
243b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 "Failed to convert device name to UTF8. %d",
244b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 GetLastError());
245b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    return -1;
246b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                }
247b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                if (productUniqueIdUTF8
248b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    && productUniqueIdUTF8Length > 0)
249b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                {
250b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                    GetProductId(deviceUniqueIdUTF8,
251b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 productUniqueIdUTF8,
252b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                 productUniqueIdUTF8Length);
253b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                }
254b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            }
255b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        }
256b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
257b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
258b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    ++index; // increase the number of valid devices
259b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
260b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
261b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VariantClear(&varName);
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            pBag->Release();
263b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            pM->Release();
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
267b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (deviceNameLength)
268b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
269b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, "%s %s",
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     __FUNCTION__, deviceNameUTF8);
271b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
272b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return index;
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
274b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2750f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.orgIBaseFilter * DeviceInfoDS::GetDeviceFilter(
276b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     const char* deviceUniqueIdUTF8,
277b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                     char* productUniqueIdUTF8,
278f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                     uint32_t productUniqueIdUTF8Length)
279b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
280b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
281f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    const int32_t deviceUniqueIdUTF8Length =
282f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org        (int32_t) strlen((char*) deviceUniqueIdUTF8); // UTF8 is also NULL terminated
283b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
284b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
285b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
286b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Device name too long");
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return NULL;
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
290b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // enumerate all video capture devices
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(_dsMonikerDevEnum);
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
293b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   &_dsMonikerDevEnum, 0);
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (hr != NOERROR)
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
296b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to enumerate CLSID_SystemDeviceEnum, error 0x%x."
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     " No webcam exist?", hr);
299b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return 0;
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _dsMonikerDevEnum->Reset();
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ULONG cFetched;
303b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IMoniker *pM;
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IBaseFilter *captureFilter = NULL;
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool deviceFound = false;
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound)
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        IPropertyBag *pBag;
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **) &pBag);
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (S_OK == hr)
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Find the description or friendly name.
314b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VARIANT varName;
315b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VariantInit(&varName);
316b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (deviceUniqueIdUTF8Length > 0)
317b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
318b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                hr = pBag->Read(L"DevicePath", &varName, 0);
319b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (FAILED(hr))
320b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
321b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    hr = pBag->Read(L"Description", &varName, 0);
322b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (FAILED(hr))
323b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
324b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        hr = pBag->Read(L"FriendlyName", &varName, 0);
325b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
326b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
327b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (SUCCEEDED(hr))
328b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
329b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    char tempDevicePathUTF8[256];
330b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    tempDevicePathUTF8[0] = 0;
331b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,
332b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        tempDevicePathUTF8,
333b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        sizeof(tempDevicePathUTF8), NULL,
334b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        NULL);
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (strncmp(tempDevicePathUTF8,
336b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                (const char*) deviceUniqueIdUTF8,
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                deviceUniqueIdUTF8Length) == 0)
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    {
339d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org                        // We have found the requested device
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        deviceFound = true;
341b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        hr = pM->BindToObject(0, 0, IID_IBaseFilter,
342b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                              (void**) &captureFilter);
343b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        if FAILED(hr)
344b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        {
345b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture,
346b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         _id, "Failed to bind to the selected capture device %d",hr);
347b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        }
348b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
349b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        if (productUniqueIdUTF8
350b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            && productUniqueIdUTF8Length > 0) // Get the device name
351b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        {
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            GetProductId(deviceUniqueIdUTF8,
354b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         productUniqueIdUTF8,
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         productUniqueIdUTF8Length);
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        }
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    }
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            VariantClear(&varName);
362b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            pBag->Release();
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            pM->Release();
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
366b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return captureFilter;
367b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
368b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
369f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::GetWindowsCapability(
37052c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    const int32_t capabilityIndex,
37152c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    VideoCaptureCapabilityWindows& windowsCapability) {
37252c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org  ReadLockScoped cs(_apiLock);
37352c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
37479c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org  if (capabilityIndex < 0 || static_cast<size_t>(capabilityIndex) >=
37579c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                                 _captureCapabilitiesWindows.size()) {
37652c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    return -1;
37779c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org  }
37852c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
37979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org  windowsCapability = _captureCapabilitiesWindows[capabilityIndex];
38052c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org  return 0;
381b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
382b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
383f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::CreateCapabilityMap(
384b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         const char* deviceUniqueIdUTF8)
385b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
386b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
387b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Reset old capability list
38852c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    _captureCapabilities.clear();
38952c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org
390f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    const int32_t deviceUniqueIdUTF8Length =
391f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org        (int32_t) strlen((char*) deviceUniqueIdUTF8);
392b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
393b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
394b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
395b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Device name too long");
396b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
397b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
398b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
399b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                 "CreateCapabilityMap called for device %s", deviceUniqueIdUTF8);
400b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
401b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
402b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char productId[kVideoCaptureProductIdLength];
4030f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    IBaseFilter* captureDevice = DeviceInfoDS::GetDeviceFilter(
404b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               deviceUniqueIdUTF8,
405b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               productId,
406b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               kVideoCaptureProductIdLength);
407b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!captureDevice)
408b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
4090f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.org    IPin* outputCapturePin = GetOutputPin(captureDevice, GUID_NULL);
410b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!outputCapturePin)
411b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
412b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
413b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to get capture device output pin");
414b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RELEASE_AND_CLEAR(captureDevice);
415b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
416b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
417b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IAMExtDevice* extDevice = NULL;
418b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr = captureDevice->QueryInterface(IID_IAMExtDevice,
419b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                               (void **) &extDevice);
420b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (SUCCEEDED(hr) && extDevice)
421b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
422b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
423b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "This is an external device");
424b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        extDevice->Release();
425b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
426b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
427b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IAMStreamConfig* streamConfig = NULL;
428b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    hr = outputCapturePin->QueryInterface(IID_IAMStreamConfig,
429b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                          (void**) &streamConfig);
430b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (FAILED(hr))
431b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
432b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
433b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to get IID_IAMStreamConfig interface from capture device");
434b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
435b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
436b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
437b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // this  gets the FPS
438b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IAMVideoControl* videoControlConfig = NULL;
439b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hrVC = captureDevice->QueryInterface(IID_IAMVideoControl,
440b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                      (void**) &videoControlConfig);
441b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (FAILED(hrVC))
442b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
443b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
444b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "IID_IAMVideoControl Interface NOT SUPPORTED");
445b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
446b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
447b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    AM_MEDIA_TYPE *pmt = NULL;
448b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    VIDEO_STREAM_CONFIG_CAPS caps;
449b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int count, size;
450b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
451b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    hr = streamConfig->GetNumberOfCapabilities(&count, &size);
452b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (FAILED(hr))
453b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
454b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
455b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to GetNumberOfCapabilities");
456b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RELEASE_AND_CLEAR(videoControlConfig);
457b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RELEASE_AND_CLEAR(streamConfig);
458b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RELEASE_AND_CLEAR(outputCapturePin);
459b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        RELEASE_AND_CLEAR(captureDevice);
460b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
461b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
462b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
463d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org    // Check if the device support formattype == FORMAT_VideoInfo2 and FORMAT_VideoInfo.
464b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Prefer FORMAT_VideoInfo since some cameras (ZureCam) has been seen having problem with MJPEG and FORMAT_VideoInfo2
465b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Interlace flag is only supported in FORMAT_VideoInfo2
466b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool supportFORMAT_VideoInfo2 = false;
467b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool supportFORMAT_VideoInfo = false;
468b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    bool foundInterlacedFormat = false;
469b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    GUID preferedVideoFormat = FORMAT_VideoInfo;
470f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    for (int32_t tmp = 0; tmp < count; ++tmp)
471b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
472b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        hr = streamConfig->GetStreamCaps(tmp, &pmt,
473b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         reinterpret_cast<BYTE*> (&caps));
474b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (!FAILED(hr))
475b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
476b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (pmt->majortype == MEDIATYPE_Video
477b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                && pmt->formattype == FORMAT_VideoInfo2)
478b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
479b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id,
480b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             " Device support FORMAT_VideoInfo2");
481b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                supportFORMAT_VideoInfo2 = true;
482b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VIDEOINFOHEADER2* h =
483b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat);
484b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                assert(h);
485b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                foundInterlacedFormat |= h->dwInterlaceFlags
486b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        & (AMINTERLACE_IsInterlaced
487b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           | AMINTERLACE_DisplayModeBobOnly);
488b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
489b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (pmt->majortype == MEDIATYPE_Video
490b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                && pmt->formattype == FORMAT_VideoInfo)
491b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
492b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id,
493b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             " Device support FORMAT_VideoInfo2");
494b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                supportFORMAT_VideoInfo = true;
495b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
496b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
497b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
498b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (supportFORMAT_VideoInfo2)
499b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
500b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (supportFORMAT_VideoInfo && !foundInterlacedFormat)
501b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
502b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            preferedVideoFormat = FORMAT_VideoInfo;
503b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
504b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        else
505b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
506b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            preferedVideoFormat = FORMAT_VideoInfo2;
507b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
508b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
509b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
510f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    for (int32_t tmp = 0; tmp < count; ++tmp)
511b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
512b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        hr = streamConfig->GetStreamCaps(tmp, &pmt,
513b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         reinterpret_cast<BYTE*> (&caps));
514b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (FAILED(hr))
515b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
516b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
517b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "Failed to GetStreamCaps");
518b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            RELEASE_AND_CLEAR(videoControlConfig);
519b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            RELEASE_AND_CLEAR(streamConfig);
520b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            RELEASE_AND_CLEAR(outputCapturePin);
521b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            RELEASE_AND_CLEAR(captureDevice);
522b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            return -1;
523b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
524b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
525b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (pmt->majortype == MEDIATYPE_Video
526b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            && pmt->formattype == preferedVideoFormat)
527b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        {
528b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
52979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org            VideoCaptureCapabilityWindows capability;
530f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org            int64_t avgTimePerFrame = 0;
531b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
532b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (pmt->formattype == FORMAT_VideoInfo)
533b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
534b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VIDEOINFOHEADER* h =
535b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    reinterpret_cast<VIDEOINFOHEADER*> (pmt->pbFormat);
536b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                assert(h);
53779c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.directShowCapabilityIndex = tmp;
53879c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.width = h->bmiHeader.biWidth;
53979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.height = h->bmiHeader.biHeight;
540b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                avgTimePerFrame = h->AvgTimePerFrame;
541b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
542b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (pmt->formattype == FORMAT_VideoInfo2)
543b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
544b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                VIDEOINFOHEADER2* h =
545b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat);
546b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                assert(h);
54779c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.directShowCapabilityIndex = tmp;
54879c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.width = h->bmiHeader.biWidth;
54979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.height = h->bmiHeader.biHeight;
55079c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.interlaced = h->dwInterlaceFlags
551b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                        & (AMINTERLACE_IsInterlaced
552b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                           | AMINTERLACE_DisplayModeBobOnly);
553b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                avgTimePerFrame = h->AvgTimePerFrame;
554b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
555b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
556b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (hrVC == S_OK)
557b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
55827329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                LONGLONG *frameDurationList;
55979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                LONGLONG maxFPS;
560b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                long listSize;
561b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                SIZE size;
56279c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                size.cx = capability.width;
56379c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                size.cy = capability.height;
564b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
565b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // GetMaxAvailableFrameRate doesn't return max frame rate always
566b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // eg: Logitech Notebook. This may be due to a bug in that API
567d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org                // because GetFrameRateList array is reversed in the above camera. So
568b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // a util method written. Can't assume the first value will return
569b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                // the max fps.
570b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                hrVC = videoControlConfig->GetFrameRateList(outputCapturePin,
571b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                            tmp, size,
572b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                            &listSize,
57327329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                                                            &frameDurationList);
574b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
57527329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                // On some odd cameras, you may get a 0 for duration.
57627329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                // GetMaxOfFrameArray returns the lowest duration (highest FPS)
57727329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                if (hrVC == S_OK && listSize > 0 &&
57879c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                    0 != (maxFPS = GetMaxOfFrameArray(frameDurationList,
57927329e94a66f2799d299c044933e59b64a4b9578vikasmarwaha@webrtc.org                                                      listSize)))
580b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
58179c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                    capability.maxFPS = static_cast<int> (10000000
582b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                           / maxFPS);
58379c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                    capability.supportFrameRateControl = true;
584b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
585b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                else // use existing method
586b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                {
587b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture,
588b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                 _id,
589b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                 "GetMaxAvailableFrameRate NOT SUPPORTED");
590b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    if (avgTimePerFrame > 0)
59179c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                        capability.maxFPS = static_cast<int> (10000000
592b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                               / avgTimePerFrame);
593b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    else
59479c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                        capability.maxFPS = 0;
595b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                }
596b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
597b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else // use existing method in case IAMVideoControl is not supported
598b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
599b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                if (avgTimePerFrame > 0)
60079c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                    capability.maxFPS = static_cast<int> (10000000
601b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                           / avgTimePerFrame);
602b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                else
60379c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                    capability.maxFPS = 0;
604b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
605b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
606b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // can't switch MEDIATYPE :~(
607b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            if (pmt->subtype == MEDIASUBTYPE_I420)
608b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
60979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoI420;
610b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
611b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_IYUV)
612b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
61379c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoIYUV;
614b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
615b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_RGB24)
616b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
61779c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoRGB24;
618b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
619b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_YUY2)
620b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
62179c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoYUY2;
622b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
623b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_RGB565)
624b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
62579c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoRGB565;
626b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
627b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_MJPG)
628b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
62979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoMJPEG;
630b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
631b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_dvsl
632b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    || pmt->subtype == MEDIASUBTYPE_dvsd
633b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                    || pmt->subtype == MEDIASUBTYPE_dvhd) // If this is an external DV camera
634b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
63579c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoYUY2;// MS DV filter seems to create this type
636b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
637b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_UYVY) // Seen used by Declink capture cards
638b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
63979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoUYVY;
640b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
641b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else if (pmt->subtype == MEDIASUBTYPE_HDYC) // Seen used by Declink capture cards. Uses BT. 709 color. Not entiry correct to use UYVY. http://en.wikipedia.org/wiki/YCbCr
642b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
643b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
644b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "Device support HDYC.");
64579c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                capability.rawType = kVideoUYVY;
646b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
647b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            else
648b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            {
649b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WCHAR strGuid[39];
650b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                StringFromGUID2(pmt->subtype, strGuid, 39);
651b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                WEBRTC_TRACE( webrtc::kTraceWarning,
652b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             webrtc::kTraceVideoCapture, _id,
653b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             "Device support unknown media type %ls, width %d, height %d",
654b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                             strGuid);
655b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                continue;
656b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            }
657b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
658b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            // Get the expected capture delay from the static list
65979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org            capability.expectedCaptureDelay
660b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                            = GetExpectedCaptureDelay(WindowsCaptureDelays,
661b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                      NoWindowsCaptureDelays,
662b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                      productId,
66379c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                                                      capability.width,
66479c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                                                      capability.height);
66579c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org            _captureCapabilities.push_back(capability);
66679c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org            _captureCapabilitiesWindows.push_back(capability);
667b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org            WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
668b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                         "Camera capability, width:%d height:%d type:%d fps:%d",
66979c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                         capability.width, capability.height,
67079c884c86807f45d9629b75b75261e9bc239643efischman@webrtc.org                         capability.rawType, capability.maxFPS);
671b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
672b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        DeleteMediaType(pmt);
673b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        pmt = NULL;
674b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
675b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(streamConfig);
676b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(videoControlConfig);
677b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(outputCapturePin);
678b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    RELEASE_AND_CLEAR(captureDevice); // Release the capture device
679d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org
680b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Store the new used device name
681b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
682b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    _lastUsedDeviceName = (char*) realloc(_lastUsedDeviceName,
683b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                   _lastUsedDeviceNameLength
684b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                       + 1);
685b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8, _lastUsedDeviceNameLength+ 1);
686b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
68752c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org                 "CreateCapabilityMap %d", _captureCapabilities.size());
688b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
68952c5c708de6f5bcf9c2a58cece45013aa5efacd7pbos@webrtc.org    return static_cast<int32_t>(_captureCapabilities.size());
690b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
691b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
692d6f6ff0da2180d5964e733ba8205c1a3353872c4henrika@webrtc.org/* Constructs a product ID from the Windows DevicePath. on a USB device the devicePath contains product id and vendor id.
693b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org This seems to work for firewire as well
694b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org /* Example of device path
695b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "\\?\usb#vid_0408&pid_2010&mi_00#7&258e7aaf&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
696b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org "\\?\avc#sony&dv-vcr&camcorder&dv#65b2d50301460008#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
697b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org */
6980f224ffecd2f1190744b5bc5c97f4ce373ba0adetommi@webrtc.orgvoid DeviceInfoDS::GetProductId(const char* devicePath,
699b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                      char* productUniqueIdUTF8,
700f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                      uint32_t productUniqueIdUTF8Length)
701b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
702b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    *productUniqueIdUTF8 = '\0';
703b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char* startPos = strstr((char*) devicePath, "\\\\?\\");
704b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!startPos)
705b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
706b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
707b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
708b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to get the product Id");
709b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return;
710b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
711b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    startPos += 4;
712b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
713b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    char* pos = strchr(startPos, '&');
714b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!pos || pos >= (char*) devicePath + strlen((char*) devicePath))
715b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
716b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
717b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
718b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to get the product Id");
719b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return;
720b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
7215c247c45aa8b51e3504cf0455e92b6704ab63fdbtommi@webrtc.org    // Find the second occurrence.
722b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    pos = strchr(pos + 1, '&');
723f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org    uint32_t bytesToCopy = (uint32_t)(pos - startPos);
724b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (pos && (bytesToCopy <= productUniqueIdUTF8Length) && bytesToCopy
725b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        <= kVideoCaptureProductIdLength)
726b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
727b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length,
728b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                  (char*) startPos, bytesToCopy);
729b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
730b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    else
731b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
732b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
733b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
734b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                     "Failed to get the product Id");
735b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
736b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
737b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
738f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.orgint32_t DeviceInfoDS::DisplayCaptureSettingsDialogBox(
739b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         const char* deviceUniqueIdUTF8,
740b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         const char* dialogTitleUTF8,
741b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                         void* parentWindow,
742f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         uint32_t positionX,
743f7e44d647cd0f893a185dfbe043cb313cab29fd0pbos@webrtc.org                                         uint32_t positionY)
744b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org{
745b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ReadLockScoped cs(_apiLock);
746b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HWND window = (HWND) parentWindow;
747b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
748b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    IBaseFilter* filter = GetDeviceFilter(deviceUniqueIdUTF8, NULL, 0);
749b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!filter)
750b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
751b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
752b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ISpecifyPropertyPages* pPages = NULL;
753b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    CAUUID uuid;
754b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    HRESULT hr = S_OK;
755b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
756b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (LPVOID*) &pPages);
757b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!SUCCEEDED(hr))
758b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
759b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        filter->Release();
760b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
761b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
762b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    hr = pPages->GetPages(&uuid);
763b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (!SUCCEEDED(hr))
764b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
765b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        filter->Release();
766b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return -1;
767b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
768b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
769b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    WCHAR tempDialogTitleWide[256];
770b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    tempDialogTitleWide[0] = 0;
771b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    int size = 255;
772b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
773b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // UTF-8 to wide char
774b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    MultiByteToWideChar(CP_UTF8, 0, (char*) dialogTitleUTF8, -1,
775b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                        tempDialogTitleWide, size);
776b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
777b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Invoke a dialog box to display.
778b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
779b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    hr = OleCreatePropertyFrame(window, // You must create the parent window.
780b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                positionX, // Horizontal position for the dialog box.
781b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                positionY, // Vertical position for the dialog box.
782b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                tempDialogTitleWide,// String used for the dialog box caption.
783b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                1, // Number of pointers passed in pPlugin.
784b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                (LPUNKNOWN*) &filter, // Pointer to the filter.
785b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                uuid.cElems, // Number of property pages.
786b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                uuid.pElems, // Array of property page CLSIDs.
787b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                LOCALE_USER_DEFAULT, // Locale ID for the dialog box.
788b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                0, NULL); // Reserved
789b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Release memory.
790b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (uuid.pElems)
791b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    {
792b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        CoTaskMemFree(uuid.pElems);
793b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
794b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    filter->Release();
795b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return 0;
796b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org}
7973b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org}  // namespace videocapturemodule
7983b89e10f31160da35b408fd00cb8f89d2b08862dpbos@webrtc.org}  // namespace webrtc
799