<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

#include <iostream>
#include <new>

#include "ref_count.h"
#include "trace.h"
#include "thread_wrapper.h"
#include "critical_section_wrapper.h"
#include "video_capture_linux.h"

namespace webrtc
{
namespace videocapturemodule
{
VideoCaptureModule* VideoCaptureImpl::Create(const WebRtc_Word32 id,
                                             const char* deviceUniqueId)
{
    RefCountImpl<videocapturemodule::VideoCaptureModuleV4L2>* implementation =
        new RefCountImpl<videocapturemodule::VideoCaptureModuleV4L2>(id);

    if (!implementation || implementation->Init(deviceUniqueId) != 0)
    {
        delete implementation;
        implementation = NULL;
    }

    return implementation;
}

VideoCaptureModuleV4L2::VideoCaptureModuleV4L2(const WebRtc_Word32 id)
    : VideoCaptureImpl(id), 
      _captureThread(NULL),
      _captureCritSect(CriticalSectionWrapper::CreateCriticalSection()),
      _deviceId(-1), 
      _deviceFd(-1),
      _buffersAllocatedByDevice(-1),
      _currentWidth(-1), 
      _currentHeight(-1),
      _currentFrameRate(-1), 
      _captureStarted(false),
      _captureVideoType(kVideoI420), 
      _pool(NULL)
{
}

WebRtc_Word32 VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8)
{
    int len = strlen((const char*) deviceUniqueIdUTF8);
    _deviceUniqueId = new (std::nothrow) char[len + 1];
    if (_deviceUniqueId)
    {
        memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
    }

    int fd;
    char device[32];
    bool found = false;

    /* detect /dev/video [0-63] entries */
    int n;
    for (n = 0; n < 64; n++)
    {
        sprintf(device, "/dev/video%d", n);
        if ((fd = open(device, O_RDONLY)) != -1)
        {
            // query device capabilities
            struct v4l2_capability cap;
            if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0)
            {
                if (cap.bus_info[0] != 0)
                {
                    if (strncmp((const char*) cap.bus_info,
                                (const char*) deviceUniqueIdUTF8,
                                strlen((const char*) deviceUniqueIdUTF8)) == 0) //match with device id
                    {
                        close(fd);
                        found = true;
                        break; // fd matches with device unique id supplied
                    }
                }
            }
            close(fd); // close since this is not the matching device
        }
    }
    if (!found)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, "no matching device found");
        return -1;
    }
    _deviceId = n; //store the device id
    return 0;
}

VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2()
{
    StopCapture();
    if (_captureCritSect)
    {
        delete _captureCritSect;
    }
    if (_deviceFd != -1)
      close(_deviceFd);
}

WebRtc_Word32 VideoCaptureModuleV4L2::StartCapture(
    const VideoCaptureCapability& capability)
{
    if (_captureStarted)
    {
        if (capability.width == _currentWidth &&
            capability.height == _currentHeight &&
            _captureVideoType == capability.rawType)
        {
            return 0;
        }
        else
        {
            StopCapture();
        }
    }

    CriticalSectionScoped cs(_captureCritSect);
    //first open /dev/video device
    char device[20];
    sprintf(device, "/dev/video%d", (int) _deviceId);

    if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                   "error in opening %s errono = %d", device, errno);
        return -1;
    }

    // Supported video formats in preferred order.
    // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
    // I420 otherwise.
    const int nFormats = 3;
    unsigned int fmts[nFormats];
    if (capability.width > 640 || capability.height > 480) {
        fmts[0] = V4L2_PIX_FMT_MJPEG;
        fmts[1] = V4L2_PIX_FMT_YUV420;
        fmts[2] = V4L2_PIX_FMT_YUYV;
    } else {
        fmts[0] = V4L2_PIX_FMT_YUV420;
        fmts[1] = V4L2_PIX_FMT_YUYV;
        fmts[2] = V4L2_PIX_FMT_MJPEG;
    }

    struct v4l2_format video_fmt;
    memset(&video_fmt, 0, sizeof(struct v4l2_format));
    video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    video_fmt.fmt.pix.sizeimage = 0;
    video_fmt.fmt.pix.width = capability.width;
    video_fmt.fmt.pix.height = capability.height;

    bool formatMatch = false;
    for (int i = 0; i < nFormats; i++)
    {
        video_fmt.fmt.pix.pixelformat = fmts[i];
        if (ioctl(_deviceFd, VIDIOC_TRY_FMT, &video_fmt) < 0)
        {
            continue;
        }
        else
        {
            formatMatch = true;
            break;
        }
    }
    if (!formatMatch)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                   "no supporting video formats found");
        return -1;
    }

    if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
        _captureVideoType = kVideoYUY2;
    else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
        _captureVideoType = kVideoI420;
    else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
        _captureVideoType = kVideoMJPEG;

    //set format and frame size now
    if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                   "error in VIDIOC_S_FMT, errno = %d", errno);
        return -1;
    }

    // initialize current width and height
    _currentWidth = video_fmt.fmt.pix.width;<commit_msg>Exchange TRY by enumerating image formats in Linux video capture<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <errno.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>

#include <iostream>
#include <new>

#include "ref_count.h"
#include "trace.h"
#include "thread_wrapper.h"
#include "critical_section_wrapper.h"
#include "video_capture_linux.h"

namespace webrtc
{
namespace videocapturemodule
{
VideoCaptureModule* VideoCaptureImpl::Create(const WebRtc_Word32 id,
                                             const char* deviceUniqueId)
{
    RefCountImpl<videocapturemodule::VideoCaptureModuleV4L2>* implementation =
        new RefCountImpl<videocapturemodule::VideoCaptureModuleV4L2>(id);

    if (!implementation || implementation->Init(deviceUniqueId) != 0)
    {
        delete implementation;
        implementation = NULL;
    }

    return implementation;
}

VideoCaptureModuleV4L2::VideoCaptureModuleV4L2(const WebRtc_Word32 id)
    : VideoCaptureImpl(id), 
      _captureThread(NULL),
      _captureCritSect(CriticalSectionWrapper::CreateCriticalSection()),
      _deviceId(-1), 
      _deviceFd(-1),
      _buffersAllocatedByDevice(-1),
      _currentWidth(-1), 
      _currentHeight(-1),
      _currentFrameRate(-1), 
      _captureStarted(false),
      _captureVideoType(kVideoI420), 
      _pool(NULL)
{
}

WebRtc_Word32 VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8)
{
    int len = strlen((const char*) deviceUniqueIdUTF8);
    _deviceUniqueId = new (std::nothrow) char[len + 1];
    if (_deviceUniqueId)
    {
        memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1);
    }

    int fd;
    char device[32];
    bool found = false;

    /* detect /dev/video [0-63] entries */
    int n;
    for (n = 0; n < 64; n++)
    {
        sprintf(device, "/dev/video%d", n);
        if ((fd = open(device, O_RDONLY)) != -1)
        {
            // query device capabilities
            struct v4l2_capability cap;
            if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == 0)
            {
                if (cap.bus_info[0] != 0)
                {
                    if (strncmp((const char*) cap.bus_info,
                                (const char*) deviceUniqueIdUTF8,
                                strlen((const char*) deviceUniqueIdUTF8)) == 0) //match with device id
                    {
                        close(fd);
                        found = true;
                        break; // fd matches with device unique id supplied
                    }
                }
            }
            close(fd); // close since this is not the matching device
        }
    }
    if (!found)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, "no matching device found");
        return -1;
    }
    _deviceId = n; //store the device id
    return 0;
}

VideoCaptureModuleV4L2::~VideoCaptureModuleV4L2()
{
    StopCapture();
    if (_captureCritSect)
    {
        delete _captureCritSect;
    }
    if (_deviceFd != -1)
      close(_deviceFd);
}

WebRtc_Word32 VideoCaptureModuleV4L2::StartCapture(
    const VideoCaptureCapability& capability)
{
    if (_captureStarted)
    {
        if (capability.width == _currentWidth &&
            capability.height == _currentHeight &&
            _captureVideoType == capability.rawType)
        {
            return 0;
        }
        else
        {
            StopCapture();
        }
    }

    CriticalSectionScoped cs(_captureCritSect);
    //first open /dev/video device
    char device[20];
    sprintf(device, "/dev/video%d", (int) _deviceId);

    if ((_deviceFd = open(device, O_RDWR | O_NONBLOCK, 0)) < 0)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                   "error in opening %s errono = %d", device, errno);
        return -1;
    }

    // Supported video formats in preferred order.
    // If the requested resolution is larger than VGA, we prefer MJPEG. Go for
    // I420 otherwise.
    const int nFormats = 3;
    unsigned int fmts[nFormats];
    if (capability.width > 640 || capability.height > 480) {
        fmts[0] = V4L2_PIX_FMT_MJPEG;
        fmts[1] = V4L2_PIX_FMT_YUV420;
        fmts[2] = V4L2_PIX_FMT_YUYV;
    } else {
        fmts[0] = V4L2_PIX_FMT_YUV420;
        fmts[1] = V4L2_PIX_FMT_YUYV;
        fmts[2] = V4L2_PIX_FMT_MJPEG;
    }

    // Enumerate image formats.
    struct v4l2_fmtdesc fmt;
    int fmtsIdx = nFormats;
    memset(&fmt, 0, sizeof(fmt));
    fmt.index = 0;
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
                 "Video Capture enumerats supported image formats:");
    while (ioctl(_deviceFd, VIDIOC_ENUM_FMT, &fmt) == 0) {
        WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
                     "  { pixelformat = %c%c%c%c, description = '%s' }",
                     fmt.pixelformat & 0xFF, (fmt.pixelformat>>8) & 0xFF,
                     (fmt.pixelformat>>16) & 0xFF, (fmt.pixelformat>>24) & 0xFF,
                     fmt.description);
        // Match the preferred order.
        for (int i = 0; i < nFormats; i++) {
            if (fmt.pixelformat == fmts[i] && i < fmtsIdx)
                fmtsIdx = i;
        }
        // Keep enumerating.
        fmt.index++;
    }

    if (fmtsIdx == nFormats)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                     "no supporting video formats found");
        return -1;
    } else {
        WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
                     "We prefer format %c%c%c%c",
                     fmts[fmtsIdx] & 0xFF, (fmts[fmtsIdx]>>8) & 0xFF,
                     (fmts[fmtsIdx]>>16) & 0xFF, (fmts[fmtsIdx]>>24) & 0xFF);
    }

    struct v4l2_format video_fmt;
    memset(&video_fmt, 0, sizeof(struct v4l2_format));
    video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    video_fmt.fmt.pix.sizeimage = 0;
    video_fmt.fmt.pix.width = capability.width;
    video_fmt.fmt.pix.height = capability.height;
    video_fmt.fmt.pix.pixelformat = fmts[fmtsIdx];

    if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV)
        _captureVideoType = kVideoYUY2;
    else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
        _captureVideoType = kVideoI420;
    else if (video_fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
        _captureVideoType = kVideoMJPEG;

    //set format and frame size now
    if (ioctl(_deviceFd, VIDIOC_S_FMT, &video_fmt) < 0)
    {
        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
                   "error in VIDIOC_S_FMT, errno = %d", errno);
        return -1;
    }

    // initialize current width and height
    _currentWidth = video_fmt.fmt.pix.width;
{'fraction_non_alphanumeric': 0.10757060476120064, 'fraction_numerical': 0.02099659914239243, 'mean_word_length': 2.304103566194431, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2645583', 'n_tokens_mistral': 4694, 'n_tokens_neox': 4466, 'n_words': 984}