14ee2ad04344446e610172a0e73949212923014dfSebastian Redl/*
22cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
32cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *
42cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  Use of this source code is governed by a BSD-style license
52cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  that can be found in the LICENSE file in the root of the source
62cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  tree. An additional intellectual property rights grant can be found
72cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  in the file PATENTS.  All contributing project authors may
82cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  be found in the AUTHORS file in the root of the source tree.
92cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */
10a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl
112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include "webrtc/modules/video_capture/linux/device_info_linux.h"
122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
132cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include <errno.h>
147faa2ec03a7ef120ac165bb45b6c70a8b20c9f1cSebastian Redl#include <fcntl.h>
1589d9980bbc2e4a4ac86673e6ec16fb9f5babb63bDouglas Gregor#include <stdio.h>
160eca89e9890db4d8336ce762a5b359a1d58ca02bArgyrios Kyrtzidis#include <stdlib.h>
17e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#include <sys/ioctl.h>
18e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#include <sys/stat.h>
192cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include <unistd.h>
202cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor//v4l includes
212cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include <linux/videodev2.h>
222a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall
2389eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis#include "webrtc/system_wrappers/interface/ref_count.h"
240b7489194f9f89fac39d57211c1e7953ae50251fDouglas Gregor#include "webrtc/system_wrappers/interface/trace.h"
257a1fad38256eb4c5129359be85ba1ea1678eb5c9John McCall
262cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
27a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCallnamespace webrtc
286ab7cd853e9c15cf986a8a7c3db1f8d20e275409Sebastian Redl{
297c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris Lattnernamespace videocapturemodule
306a5a23f8e7fb65e028c8092bc1d1a1d9dfe2e9bcDouglas Gregor{
317c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris LattnerVideoCaptureModule::DeviceInfo*
3283d63c78810556d26b62ac4cbae2eda6cdd2570cSteve NaroffVideoCaptureImpl::CreateDeviceInfo(const int32_t id)
3314f79002e58556798e86168c63e48d533287eda5Douglas Gregor{
3410e286aa8d39fb51a21412850265d9dae74613eeChris Lattner    videocapturemodule::DeviceInfoLinux *deviceInfo =
353251ceb90b3fec68e86d6dcfa58836e20a7205c3Douglas Gregor                    new videocapturemodule::DeviceInfoLinux(id);
3614f79002e58556798e86168c63e48d533287eda5Douglas Gregor    if (!deviceInfo)
37bd94500d3aa60092fb0f1e90f53fb0d03fa502a8Douglas Gregor    {
382bec0410d268779f601bd509e0302a500af7ac6aDouglas Gregor        deviceInfo = NULL;
39ab41e63821dc60ad144d0684df8d79a9eef86b75Douglas Gregor    }
400a0d2b179085a52c10402feebeb6db8b4d96a140Douglas Gregor
4117fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor    return deviceInfo;
4217fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor}
432596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar
442cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorDeviceInfoLinux::DeviceInfoLinux(const int32_t id)
45fbfd180495e7800975c6d9bdc6d24e706ef70e34Michael J. Spencer    : DeviceInfoImpl(id)
4614f79002e58556798e86168c63e48d533287eda5Douglas Gregor{
4703013fa9a0bf1ef4b907f5fec006c8f4000fdd21Michael J. Spencer}
48f62d43d2afe1960755a1b5813cae1e5983bcac1bDouglas Gregor
493c304bd9ec2b4611572d4cbae9e1727bbecb5dc9Chris Lattnerint32_t DeviceInfoLinux::Init()
50cfbf1c7536e016dc275139dd842d4a5f059a749fDouglas Gregor{
51f62d43d2afe1960755a1b5813cae1e5983bcac1bDouglas Gregor    return 0;
522cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
538538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl
542cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorDeviceInfoLinux::~DeviceInfoLinux()
55ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl{
565f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner}
575f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner
585f9e272e632e951b1efe824cd16acb4d96077930Chris Lattneruint32_t DeviceInfoLinux::NumberOfDevices()
596e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer{
60ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl    WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCapture, _id, "%s", __FUNCTION__);
616e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer
626e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer    uint32_t count = 0;
635f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    char device[20];
645f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner    int fd = -1;
656e089c687cc2b914c46859ab7e46fe4c3c6b0afbBenjamin Kramer
66ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl    /* detect /dev/video [0-63]VideoCaptureModule entries */
67ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl    for (int n = 0; n < 64; n++)
682cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
692cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        sprintf(device, "/dev/video%d", n);
702cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        if ((fd = open(device, O_RDONLY)) != -1)
7112b1c7615d4f9a2edc544be499f895f16ac100edChris Lattner        {
722cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            close(fd);
733397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            count++;
74a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl        }
7589eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis    }
762cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
772cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    return count;
782cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
798538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl
802cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregorint32_t DeviceInfoLinux::GetDeviceName(
8189eaf3af92c72c0c1aae807644e39cabc461d685Argyrios Kyrtzidis                                         uint32_t deviceNumber,
828538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                                         char* deviceNameUTF8,
832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                         uint32_t deviceNameLength,
842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                         char* deviceUniqueIdUTF8,
852cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                         uint32_t deviceUniqueIdUTF8Length,
862cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                         char* /*productUniqueIdUTF8*/,
872cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                         uint32_t /*productUniqueIdUTF8Length*/)
882cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor{
892cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCapture, _id, "%s", __FUNCTION__);
902cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
912cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // Travel through /dev/video [0-63]
922cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    uint32_t count = 0;
932cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    char device[20];
943397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    int fd = -1;
952cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    bool found = false;
962cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    for (int n = 0; n < 64; n++)
972cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
983397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl        sprintf(device, "/dev/video%d", n);
992cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        if ((fd = open(device, O_RDONLY)) != -1)
1008538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        {
1012cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            if (count == deviceNumber) {
1022cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                // Found the device
1033397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl                found = true;
1042cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                break;
1058538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl            } else {
1062cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                close(fd);
1072cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                count++;
1083397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            }
1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump        }
1108538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    }
1112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    if (!found)
1133397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl        return -1;
114df1550fc59b51681d37225934fe4e3acac321621Richard Smith
115df1550fc59b51681d37225934fe4e3acac321621Richard Smith    // query device capabilities
1168538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    struct v4l2_capability cap;
1172cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
1182cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
1193397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
120df1550fc59b51681d37225934fe4e3acac321621Richard Smith                   "error in querying the device capability for device %s. errno = %d",
1218538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                   device, errno);
1222cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        close(fd);
1232cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        return -1;
1243397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    }
1251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1261eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    close(fd);
1278538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl
1282cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    char cameraName[64];
1292cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    memset(deviceNameUTF8, 0, deviceNameLength);
1303397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    memcpy(cameraName, cap.card, sizeof(cap.card));
1312cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1322cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    if (deviceNameLength >= strlen(cameraName))
1330953e767ff7817f97b3ab20896b229891eeff45bJohn McCall    {
1342cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        memcpy(deviceNameUTF8, cameraName, strlen(cameraName));
1352cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
1363397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    else
1372cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
1382cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, "buffer passed is too small");
1398538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        return -1;
1402cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
1412cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1423397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    if (cap.bus_info[0] != 0) // may not available in all drivers
1432cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
1448538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        // copy device id
1452cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        if (deviceUniqueIdUTF8Length >= strlen((const char*) cap.bus_info))
1462cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        {
1473397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            memset(deviceUniqueIdUTF8, 0, deviceUniqueIdUTF8Length);
1482cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            memcpy(deviceUniqueIdUTF8, cap.bus_info,
1497e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor                   strlen((const char*) cap.bus_info));
1507e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor        }
151c9490c000f515c29f200a1215328d8ab9a0f3818Douglas Gregor        else
1528538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        {
1532cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
1542cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                       "buffer passed is too small");
1553397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            return -1;
1562cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        }
1572cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
158e86d78cf4754a6aef2cf9a33d847aa15338e276fBob Wilson
1598538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    return 0;
1602cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
1612cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1623397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redlint32_t DeviceInfoLinux::CreateCapabilityMap(
1632cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                        const char* deviceUniqueIdUTF8)
1648538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl{
1652cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    int fd;
1662cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    char device[32];
1673397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    bool found = false;
1682cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
169264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola    const int32_t deviceUniqueIdUTF8Length =
170264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola                            (int32_t) strlen((char*) deviceUniqueIdUTF8);
171a49218e17bcbb1acde0245773173e2c0c42f4f19Eli Friedman    if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
172425ef72306d4ff6b3698b744353e5f0e56b4b884Rafael Espindola    {
173ab8bbf4ebd3e3e6eab913cb044772a62b7581941Douglas Gregor        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, "Device name too long");
174264ba48dc98f3f843935a485d5b086f7e0fdc4f1Rafael Espindola        return -1;
175f85e193739c953358c865005855253af4f68a497John McCall    }
1762cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
1772cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor               "CreateCapabilityMap called for device %s", deviceUniqueIdUTF8);
1783397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
1792cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    /* detect /dev/video [0-63] entries */
1808538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    for (int n = 0; n < 64; ++n)
1812cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    {
1822cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        sprintf(device, "/dev/video%d", n);
1833397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl        fd = open(device, O_RDONLY);
1842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        if (fd == -1)
1852cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor          continue;
1862cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1872cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        // query device capabilities
1882cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        struct v4l2_capability cap;
1892cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0)
190c938c1668b4fd12af154e965dd935a89e4801a70Douglas Gregor        {
19160618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl            if (cap.bus_info[0] != 0)
19260618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl            {
19360618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                if (strncmp((const char*) cap.bus_info,
19460618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                            (const char*) deviceUniqueIdUTF8,
19560618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                            strlen((const char*) deviceUniqueIdUTF8)) == 0) //match with device id
19660618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                {
19760618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                    found = true;
19860618fa7f88d5162bb5b40988b6b38d4d75d6fc6Sebastian Redl                    break; // fd matches with device unique id supplied
1998538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                }
2002cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            }
2012cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            else //match for device name
2023397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            {
203ed97649e9574b9d854fa4d6109c9333ae0993554John McCall                if (IsDeviceNameMatches((const char*) cap.card,
2048538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                                        (const char*) deviceUniqueIdUTF8))
205ed97649e9574b9d854fa4d6109c9333ae0993554John McCall                {
206ed97649e9574b9d854fa4d6109c9333ae0993554John McCall                    found = true;
2073397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl                    break;
2082cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                }
2099763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis            }
2109763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis        }
2118538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        close(fd); // close since this is not the matching device
2122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
2132cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
2143397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    if (!found)
215c9490c000f515c29f200a1215328d8ab9a0f3818Douglas Gregor    {
2168538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, "no matching device found");
2172cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor        return -1;
2182cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
2193397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
2202cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // now fd will point to the matching device
2218538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    // reset old capability list.
2222cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    _captureCapabilities.clear();
2232cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
2243397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    int size = FillCapabilities(fd);
225395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson    close(fd);
2268538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl
227395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson    // Store the new used device name
228395b475a4474f1c7574d927ad142ca0c7997cbcaAnders Carlsson    _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
229ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt    _lastUsedDeviceName = (char*) realloc(_lastUsedDeviceName,
230ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt                                                   _lastUsedDeviceNameLength + 1);
231ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt    memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8, _lastUsedDeviceNameLength + 1);
232ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt
233ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt    WEBRTC_TRACE(webrtc::kTraceInfo,
234ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt                 webrtc::kTraceVideoCapture,
235ca63c200346c0ca9e00194ec6e34a5a7b0ed9321Sean Hunt                 _id,
23634b41d939a1328f484511c6002ba2456db879a29Richard Smith                 "CreateCapabilityMap %u",
23734b41d939a1328f484511c6002ba2456db879a29Richard Smith                 static_cast<unsigned int>(_captureCapabilities.size()));
23834b41d939a1328f484511c6002ba2456db879a29Richard Smith
23934b41d939a1328f484511c6002ba2456db879a29Richard Smith    return size;
24034b41d939a1328f484511c6002ba2456db879a29Richard Smith}
2413397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
242be191100e034b23a3e13053757a57b7f5068c24aArgyrios Kyrtzidisbool DeviceInfoLinux::IsDeviceNameMatches(const char* name,
2432cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor                                          const char* deviceUniqueIdUTF8)
2441eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump{
2452cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    if (strncmp(deviceUniqueIdUTF8, name, strlen(name)) == 0)
2462cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            return true;
2472cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    return false;
2483397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl}
2492cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
2508538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redlint32_t DeviceInfoLinux::FillCapabilities(int fd)
2512cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor{
2522cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
2533397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    // set image format
2542cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    struct v4l2_format video_fmt;
2558538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    memset(&video_fmt, 0, sizeof(struct v4l2_format));
2562cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
2572cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2589d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall    video_fmt.fmt.pix.sizeimage = 0;
2599d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall
2609d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall    int totalFmts = 3;
2619d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall    unsigned int videoFormats[] = {
2629d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall        V4L2_PIX_FMT_MJPEG,
2639d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall        V4L2_PIX_FMT_YUV420,
2649d156a7b1b2771e191f2f5a45a7b7a694129463bJohn McCall        V4L2_PIX_FMT_YUYV };
2651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2663397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    int sizes = 13;
26749a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall    unsigned int size[][2] = { { 128, 96 }, { 160, 120 }, { 176, 144 },
26849a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall                               { 320, 240 }, { 352, 288 }, { 640, 480 },
26949a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall                               { 704, 576 }, { 800, 600 }, { 960, 720 },
2708538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                               { 1280, 720 }, { 1024, 768 }, { 1440, 1080 },
27149a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall                               { 1920, 1080 } };
27249a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall
27349a832bd499d6f61c23655f1fac99f0dd229756eJohn McCall    int index = 0;
274c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor    for (int fmts = 0; fmts < totalFmts; fmts++)
275c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor    {
276c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor        for (int i = 0; i < sizes; i++)
277c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor        {
278c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor            video_fmt.fmt.pix.pixelformat = videoFormats[fmts];
279c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor            video_fmt.fmt.pix.width = size[i][0];
280c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor            video_fmt.fmt.pix.height = size[i][1];
281c3069d618f4661d923cb1b5c4525b082fce73b04Douglas Gregor
2823397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl            if (ioctl(fd, VIDIOC_TRY_FMT, &video_fmt) >= 0)
2832cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor            {
284be191100e034b23a3e13053757a57b7f5068c24aArgyrios Kyrtzidis                if ((video_fmt.fmt.pix.width == size[i][0])
28590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    && (video_fmt.fmt.pix.height == size[i][1]))
28690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                {
28790b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    VideoCaptureCapability cap;
28890b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    cap.width = video_fmt.fmt.pix.width;
28990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    cap.height = video_fmt.fmt.pix.height;
2903e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith                    cap.expectedCaptureDelay = 120;
2913e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith                    if (videoFormats[fmts] == V4L2_PIX_FMT_YUYV)
2929763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis                    {
2939763e221e16026ddf487d2564ed349d2c874a1a1Argyrios Kyrtzidis                        cap.rawType = kVideoYUY2;
2948538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                    }
29590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    else if (videoFormats[fmts] == V4L2_PIX_FMT_YUV420)
29690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    {
29790b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                        cap.rawType = kVideoI420;
2983397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl                    }
299ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios Kyrtzidis                    else if (videoFormats[fmts] == V4L2_PIX_FMT_MJPEG)
300ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios Kyrtzidis                    {
301ae8b17f1d5d303af53db5a4f4a375ea6b9356566Argyrios Kyrtzidis                        cap.rawType = kVideoMJPEG;
3028538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                    }
30390b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis
30490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    // get fps of current camera mode
30590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    // V4l2 does not have a stable method of knowing so we just guess.
3063397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl                    if(cap.width >= 800 && cap.rawType != kVideoMJPEG)
30790b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    {
30890b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                        cap.maxFPS = 15;
30990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    }
31090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    else
31190b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    {
31290b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                        cap.maxFPS = 30;
3133397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl                    }
31490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis
31590b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    _captureCapabilities.push_back(cap);
31690b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                    index++;
3174fb86f8c4585e53c21c847ad3de9e3b2de123cd9Chandler Carruth                    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
3188538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                               "Camera capability, width:%d height:%d type:%d fps:%d",
31990b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                               cap.width, cap.height, cap.rawType, cap.maxFPS);
32090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis                }
32190b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis            }
3223397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl        }
3238dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis    }
3248dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis
3258dfbd8b252ba4e6cf4b7a3422f6ef0ca21312dfeArgyrios Kyrtzidis    WEBRTC_TRACE(webrtc::kTraceInfo,
326f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis                 webrtc::kTraceVideoCapture,
327f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis                 _id,
328f48d45e3e36c132bdee3373beec4e8b19ae3f9c4Argyrios Kyrtzidis                 "CreateCapabilityMap %u",
3298538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl                 static_cast<unsigned int>(_captureCapabilities.size()));
33090b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis    return _captureCapabilities.size();
33190b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis}
33290b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis
3333397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl}  // namespace videocapturemodule
33490b715e0df34eae2b50b9b43ec60828ed31dcf94Argyrios Kyrtzidis}  // namespace webrtc
3353acad62a239448bef0f5848b2a0d5f7dfefd3d14Argyrios Kyrtzidis