| Index: media/video/capture/linux/video_capture_device_linux.cc
|
| diff --git a/media/video/capture/linux/video_capture_device_linux.cc b/media/video/capture/linux/video_capture_device_linux.cc
|
| index 500be2c8fff3285669707ca8be10eecbc7a88e52..b9fb195f8ae4b0e670b7c482bd3a5245460f35c8 100644
|
| --- a/media/video/capture/linux/video_capture_device_linux.cc
|
| +++ b/media/video/capture/linux/video_capture_device_linux.cc
|
| @@ -4,20 +4,100 @@
|
|
|
| #include "media/video/capture/linux/video_capture_device_linux.h"
|
|
|
| +#include <errno.h>
|
| +#include <fcntl.h>
|
| +#include <poll.h>
|
| #if defined(OS_OPENBSD)
|
| #include <sys/videoio.h>
|
| #else
|
| #include <linux/videodev2.h>
|
| #endif
|
| +#include <sys/ioctl.h>
|
| +#include <sys/mman.h>
|
|
|
| #include <list>
|
| #include <string>
|
|
|
| #include "base/bind.h"
|
| +#include "base/files/file_enumerator.h"
|
| +#include "base/files/scoped_file.h"
|
| +#include "base/posix/eintr_wrapper.h"
|
| #include "base/strings/stringprintf.h"
|
| -#include "media/video/capture/linux/v4l2_capture_delegate.h"
|
|
|
| namespace media {
|
| +
|
| +#define GET_V4L2_FOURCC_CHAR(a, index) ((char)( ((a) >> (8 * index)) & 0xff))
|
| +
|
| +// Desired number of video buffers to allocate. The actual number of allocated
|
| +// buffers by v4l2 driver can be higher or lower than this number.
|
| +// kNumVideoBuffers should not be too small, or Chrome may not return enough
|
| +// buffers back to driver in time.
|
| +const uint32 kNumVideoBuffers = 4;
|
| +// Timeout in milliseconds v4l2_thread_ blocks waiting for a frame from the hw.
|
| +enum { kCaptureTimeoutMs = 200 };
|
| +// The number of continuous timeouts tolerated before treated as error.
|
| +enum { kContinuousTimeoutLimit = 10 };
|
| +// MJPEG is preferred if the width or height is larger than this.
|
| +enum { kMjpegWidth = 640 };
|
| +enum { kMjpegHeight = 480 };
|
| +// Typical framerate, in fps
|
| +enum { kTypicalFramerate = 30 };
|
| +
|
| +class VideoCaptureDeviceLinux::V4L2CaptureDelegate
|
| + : public base::RefCountedThreadSafe<V4L2CaptureDelegate>{
|
| + public:
|
| + V4L2CaptureDelegate(
|
| + const Name& device_name,
|
| + const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner,
|
| + int power_line_frequency);
|
| +
|
| + void AllocateAndStart(int width,
|
| + int height,
|
| + float frame_rate,
|
| + scoped_ptr<Client> client);
|
| + void StopAndDeAllocate();
|
| + void SetRotation(int rotation);
|
| + bool DeAllocateVideoBuffers();
|
| +
|
| + private:
|
| + // Buffers used to receive captured frames from v4l2.
|
| + struct Buffer {
|
| + Buffer() : start(0), length(0) {}
|
| + void* start;
|
| + size_t length;
|
| + };
|
| +
|
| + friend class base::RefCountedThreadSafe<V4L2CaptureDelegate>;
|
| + ~V4L2CaptureDelegate();
|
| +
|
| + void DoCapture();
|
| + bool AllocateVideoBuffers();
|
| + void SetErrorState(const std::string& reason);
|
| +
|
| + const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner_;
|
| +
|
| + bool is_capturing_;
|
| + scoped_ptr<VideoCaptureDevice::Client> client_;
|
| + const Name device_name_;
|
| + base::ScopedFD device_fd_; // File descriptor for the opened camera device.
|
| + Buffer* buffer_pool_;
|
| + int buffer_pool_size_; // Number of allocated buffers.
|
| + int timeout_count_;
|
| + VideoCaptureFormat capture_format_;
|
| + const int power_line_frequency_;
|
| +
|
| + // Clockwise rotation in degrees. This value should be 0, 90, 180, or 270.
|
| + int rotation_;
|
| +
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(V4L2CaptureDelegate);
|
| +};
|
| +
|
| +// V4L2 color formats VideoCaptureDeviceLinux support.
|
| +static const int32 kV4l2RawFmts[] = {
|
| + V4L2_PIX_FMT_YUV420,
|
| + V4L2_PIX_FMT_YUYV,
|
| + V4L2_PIX_FMT_UYVY
|
| +};
|
|
|
| // USB VID and PID are both 4 bytes long.
|
| static const size_t kVidPidSize = 4;
|
| @@ -42,18 +122,48 @@
|
| return true;
|
| }
|
|
|
| -// Translates Video4Linux pixel formats to Chromium pixel formats.
|
| +// This function translates Video4Linux pixel formats to Chromium pixel formats,
|
| +// should only support those listed in GetListOfUsableFourCCs.
|
| // static
|
| VideoPixelFormat VideoCaptureDeviceLinux::V4l2FourCcToChromiumPixelFormat(
|
| uint32 v4l2_fourcc) {
|
| - return V4L2CaptureDelegate::V4l2FourCcToChromiumPixelFormat(v4l2_fourcc);
|
| -}
|
| -
|
| -// Gets a list of usable Four CC formats prioritised.
|
| + const struct {
|
| + uint32 fourcc;
|
| + VideoPixelFormat pixel_format;
|
| + } kFourCcAndChromiumPixelFormat[] = {
|
| + {V4L2_PIX_FMT_YUV420, PIXEL_FORMAT_I420},
|
| + {V4L2_PIX_FMT_YUYV, PIXEL_FORMAT_YUY2},
|
| + {V4L2_PIX_FMT_UYVY, PIXEL_FORMAT_UYVY},
|
| + {V4L2_PIX_FMT_MJPEG, PIXEL_FORMAT_MJPEG},
|
| + {V4L2_PIX_FMT_JPEG, PIXEL_FORMAT_MJPEG},
|
| + };
|
| + for (const auto& fourcc_and_pixel_format : kFourCcAndChromiumPixelFormat) {
|
| + if (fourcc_and_pixel_format.fourcc == v4l2_fourcc)
|
| + return fourcc_and_pixel_format.pixel_format;
|
| + }
|
| + DVLOG(1) << "Unsupported pixel format: "
|
| + << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 0)
|
| + << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 1)
|
| + << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 2)
|
| + << GET_V4L2_FOURCC_CHAR(v4l2_fourcc, 3);
|
| + return PIXEL_FORMAT_UNKNOWN;
|
| +}
|
| +
|
| // static
|
| -std::list<uint32_t> VideoCaptureDeviceLinux::GetListOfUsableFourCCs(
|
| +std::list<int> VideoCaptureDeviceLinux::GetListOfUsableFourCCs(
|
| bool favour_mjpeg) {
|
| - return V4L2CaptureDelegate::GetListOfUsableFourCcs(favour_mjpeg);
|
| + std::list<int> fourccs;
|
| + for (size_t i = 0; i < arraysize(kV4l2RawFmts); ++i)
|
| + fourccs.push_back(kV4l2RawFmts[i]);
|
| + if (favour_mjpeg)
|
| + fourccs.push_front(V4L2_PIX_FMT_MJPEG);
|
| + else
|
| + fourccs.push_back(V4L2_PIX_FMT_MJPEG);
|
| +
|
| + // JPEG works as MJPEG on some gspca webcams from field reports.
|
| + // Put it as the least preferred format.
|
| + fourccs.push_back(V4L2_PIX_FMT_JPEG);
|
| + return fourccs;
|
| }
|
|
|
| const std::string VideoCaptureDevice::Name::GetModel() const {
|
| @@ -97,21 +207,18 @@
|
| if (v4l2_thread_.IsRunning())
|
| return; // Wrong state.
|
| v4l2_thread_.Start();
|
| -
|
| - const int line_frequency =
|
| - TranslatePowerLineFrequencyToV4L2(GetPowerLineFrequencyForLocation());
|
| - capture_impl_ = V4L2CaptureDelegate::CreateV4L2CaptureDelegate(
|
| - device_name_, v4l2_thread_.message_loop_proxy(), line_frequency);
|
| - if (!capture_impl_) {
|
| - client->OnError("Failed to create VideoCaptureDelegate");
|
| - return;
|
| - }
|
| + capture_impl_ = new V4L2CaptureDelegate(device_name_,
|
| + v4l2_thread_.message_loop_proxy(),
|
| + GetPowerLineFrequencyForLocation());
|
| v4l2_thread_.message_loop()->PostTask(
|
| FROM_HERE,
|
| - base::Bind(&V4L2CaptureDelegate::AllocateAndStart, capture_impl_,
|
| - params.requested_format.frame_size.width(),
|
| - params.requested_format.frame_size.height(),
|
| - params.requested_format.frame_rate, base::Passed(&client)));
|
| + base::Bind(
|
| + &VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateAndStart,
|
| + capture_impl_,
|
| + params.requested_format.frame_size.width(),
|
| + params.requested_format.frame_size.height(),
|
| + params.requested_format.frame_rate,
|
| + base::Passed(&client)));
|
| }
|
|
|
| void VideoCaptureDeviceLinux::StopAndDeAllocate() {
|
| @@ -119,31 +226,309 @@
|
| return; // Wrong state.
|
| v4l2_thread_.message_loop()->PostTask(
|
| FROM_HERE,
|
| - base::Bind(&V4L2CaptureDelegate::StopAndDeAllocate, capture_impl_));
|
| + base::Bind(
|
| + &VideoCaptureDeviceLinux::V4L2CaptureDelegate::StopAndDeAllocate,
|
| + capture_impl_));
|
| v4l2_thread_.Stop();
|
| -
|
| + // TODO(mcasas): VCDLinux called DeAllocateVideoBuffers() a second time after
|
| + // stopping |v4l2_thread_| to make sure buffers were completely deallocated.
|
| + // Investigate if that's needed, otherwise remove the following line and make
|
| + // V4L2CaptureDelegate::DeAllocateVideoBuffers() private.
|
| + capture_impl_->DeAllocateVideoBuffers();
|
| capture_impl_ = NULL;
|
| }
|
|
|
| void VideoCaptureDeviceLinux::SetRotation(int rotation) {
|
| if (v4l2_thread_.IsRunning()) {
|
| v4l2_thread_.message_loop()->PostTask(
|
| - FROM_HERE, base::Bind(&V4L2CaptureDelegate::SetRotation,
|
| - capture_impl_, rotation));
|
| - }
|
| -}
|
| -
|
| -// static
|
| -int VideoCaptureDeviceLinux::TranslatePowerLineFrequencyToV4L2(int frequency) {
|
| - switch (frequency) {
|
| - case kPowerLine50Hz:
|
| - return V4L2_CID_POWER_LINE_FREQUENCY_50HZ;
|
| - case kPowerLine60Hz:
|
| - return V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
|
| - default:
|
| - // If we have no idea of the frequency, at least try and set it to AUTO.
|
| - return V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
|
| - }
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetRotation,
|
| + capture_impl_,
|
| + rotation));
|
| + }
|
| +}
|
| +
|
| +VideoCaptureDeviceLinux::V4L2CaptureDelegate::V4L2CaptureDelegate(
|
| + const Name& device_name,
|
| + const scoped_refptr<base::SingleThreadTaskRunner> v4l2_task_runner,
|
| + int power_line_frequency)
|
| + : v4l2_task_runner_(v4l2_task_runner),
|
| + is_capturing_(false),
|
| + device_name_(device_name),
|
| + buffer_pool_(NULL),
|
| + buffer_pool_size_(0),
|
| + timeout_count_(0),
|
| + power_line_frequency_(power_line_frequency),
|
| + rotation_(0) {
|
| +}
|
| +
|
| +VideoCaptureDeviceLinux::V4L2CaptureDelegate::~V4L2CaptureDelegate() {
|
| + DCHECK(!client_);
|
| +}
|
| +
|
| +void VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateAndStart(
|
| + int width,
|
| + int height,
|
| + float frame_rate,
|
| + scoped_ptr<Client> client) {
|
| + DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
|
| + DCHECK(client);
|
| + client_ = client.Pass();
|
| +
|
| + // Need to open camera with O_RDWR after Linux kernel 3.3.
|
| + device_fd_.reset(HANDLE_EINTR(open(device_name_.id().c_str(), O_RDWR)));
|
| + if (!device_fd_.is_valid()) {
|
| + SetErrorState("Failed to open V4L2 device driver file.");
|
| + return;
|
| + }
|
| +
|
| + v4l2_capability cap = {};
|
| + if (!((HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYCAP, &cap)) == 0) &&
|
| + (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE &&
|
| + !(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)))) {
|
| + device_fd_.reset();
|
| + SetErrorState("This is not a V4L2 video capture device");
|
| + return;
|
| + }
|
| +
|
| + // Get supported video formats in preferred order.
|
| + // For large resolutions, favour mjpeg over raw formats.
|
| + const std::list<int>& desired_v4l2_formats =
|
| + GetListOfUsableFourCCs(width > kMjpegWidth || height > kMjpegHeight);
|
| + std::list<int>::const_iterator best = desired_v4l2_formats.end();
|
| +
|
| + v4l2_fmtdesc fmtdesc = {};
|
| + fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + for (; HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_ENUM_FMT, &fmtdesc)) == 0;
|
| + ++fmtdesc.index) {
|
| + best = std::find(desired_v4l2_formats.begin(), best, fmtdesc.pixelformat);
|
| + }
|
| + if (best == desired_v4l2_formats.end()) {
|
| + SetErrorState("Failed to find a supported camera format.");
|
| + return;
|
| + }
|
| +
|
| + v4l2_format video_fmt = {};
|
| + video_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + video_fmt.fmt.pix.sizeimage = 0;
|
| + video_fmt.fmt.pix.width = width;
|
| + video_fmt.fmt.pix.height = height;
|
| + video_fmt.fmt.pix.pixelformat = *best;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_FMT, &video_fmt)) < 0) {
|
| + SetErrorState("Failed to set video capture format");
|
| + return;
|
| + }
|
| +
|
| + // Set capture framerate in the form of capture interval.
|
| + v4l2_streamparm streamparm = {};
|
| + streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + // The following line checks that the driver knows about framerate get/set.
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_G_PARM, &streamparm)) >= 0) {
|
| + // Now check if the device is able to accept a capture framerate set.
|
| + if (streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
|
| + // |frame_rate| is float, approximate by a fraction.
|
| + streamparm.parm.capture.timeperframe.numerator =
|
| + media::kFrameRatePrecision;
|
| + streamparm.parm.capture.timeperframe.denominator = (frame_rate) ?
|
| + (frame_rate * media::kFrameRatePrecision) :
|
| + (kTypicalFramerate * media::kFrameRatePrecision);
|
| +
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_PARM, &streamparm)) <
|
| + 0) {
|
| + SetErrorState("Failed to set camera framerate");
|
| + return;
|
| + }
|
| + DVLOG(2) << "Actual camera driverframerate: "
|
| + << streamparm.parm.capture.timeperframe.denominator << "/"
|
| + << streamparm.parm.capture.timeperframe.numerator;
|
| + }
|
| + }
|
| + // TODO(mcasas): what should be done if the camera driver does not allow
|
| + // framerate configuration, or the actual one is different from the desired?
|
| +
|
| + // Set anti-banding/anti-flicker to 50/60Hz. May fail due to not supported
|
| + // operation (|errno| == EINVAL in this case) or plain failure.
|
| + if ((power_line_frequency_ == kPowerLine50Hz) ||
|
| + (power_line_frequency_ == kPowerLine60Hz)) {
|
| + struct v4l2_control control = {};
|
| + control.id = V4L2_CID_POWER_LINE_FREQUENCY;
|
| + control.value = (power_line_frequency_ == kPowerLine50Hz)
|
| + ? V4L2_CID_POWER_LINE_FREQUENCY_50HZ
|
| + : V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
|
| + HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_S_CTRL, &control));
|
| + }
|
| +
|
| + capture_format_.frame_size.SetSize(video_fmt.fmt.pix.width,
|
| + video_fmt.fmt.pix.height);
|
| + capture_format_.frame_rate = frame_rate;
|
| + capture_format_.pixel_format =
|
| + V4l2FourCcToChromiumPixelFormat(video_fmt.fmt.pix.pixelformat);
|
| +
|
| + if (!AllocateVideoBuffers()) {
|
| + SetErrorState("Allocate buffer failed (Cannot recover from this error)");
|
| + return;
|
| + }
|
| +
|
| + const v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMON, &type)) < 0) {
|
| + SetErrorState("VIDIOC_STREAMON failed");
|
| + return;
|
| + }
|
| +
|
| + is_capturing_ = true;
|
| + // Post task to start fetching frames from v4l2.
|
| + v4l2_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture,
|
| + this));
|
| +}
|
| +
|
| +void VideoCaptureDeviceLinux::V4L2CaptureDelegate::StopAndDeAllocate() {
|
| + DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
|
| +
|
| + const v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_STREAMOFF, &type)) < 0) {
|
| + SetErrorState("VIDIOC_STREAMOFF failed");
|
| + return;
|
| + }
|
| + // We don't dare to deallocate the buffers if we can't stop the capture
|
| + // device.
|
| + if (!DeAllocateVideoBuffers())
|
| + SetErrorState("Failed to reset buffers");
|
| +
|
| + // We need to close and open the device if we want to change the settings.
|
| + // Otherwise VIDIOC_S_FMT will return error. Sad but true.
|
| + device_fd_.reset();
|
| + is_capturing_ = false;
|
| + client_.reset();
|
| +}
|
| +
|
| +void VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetRotation(int rotation) {
|
| + DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
|
| + DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
|
| + rotation_ = rotation;
|
| +}
|
| +
|
| +void VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture() {
|
| + DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
|
| + if (!is_capturing_)
|
| + return;
|
| +
|
| + pollfd device_pfd = {};
|
| + device_pfd.fd = device_fd_.get();
|
| + device_pfd.events = POLLIN;
|
| + const int result = HANDLE_EINTR(poll(&device_pfd, 1, kCaptureTimeoutMs));
|
| + if (result < 0) {
|
| + SetErrorState("Poll failed");
|
| + return;
|
| + }
|
| + // Check if poll() timed out; track the amount of times it did in a row and
|
| + // throw an error if it times out too many times.
|
| + if (result == 0) {
|
| + timeout_count_++;
|
| + if (timeout_count_ >= kContinuousTimeoutLimit) {
|
| + SetErrorState("Multiple continuous timeouts while read-polling.");
|
| + timeout_count_ = 0;
|
| + return;
|
| + }
|
| + } else {
|
| + timeout_count_ = 0;
|
| + }
|
| +
|
| + // Check if the driver has filled a buffer.
|
| + if (device_pfd.revents & POLLIN) {
|
| + v4l2_buffer buffer = {};
|
| + buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + buffer.memory = V4L2_MEMORY_MMAP;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_DQBUF, &buffer)) < 0) {
|
| + SetErrorState("Failed to dequeue capture buffer");
|
| + return;
|
| + }
|
| + client_->OnIncomingCapturedData(
|
| + static_cast<uint8*>(buffer_pool_[buffer.index].start),
|
| + buffer.bytesused,
|
| + capture_format_,
|
| + rotation_,
|
| + base::TimeTicks::Now());
|
| +
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0)
|
| + SetErrorState("Failed to enqueue capture buffer");
|
| + }
|
| +
|
| + v4l2_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureDeviceLinux::V4L2CaptureDelegate::DoCapture,
|
| + this));
|
| +}
|
| +
|
| +bool VideoCaptureDeviceLinux::V4L2CaptureDelegate::AllocateVideoBuffers() {
|
| + v4l2_requestbuffers r_buffer = {};
|
| + r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + r_buffer.memory = V4L2_MEMORY_MMAP;
|
| + r_buffer.count = kNumVideoBuffers;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0) {
|
| + DLOG(ERROR) << "Error requesting MMAP buffers from V4L2";
|
| + return false;
|
| + }
|
| + buffer_pool_size_ = r_buffer.count;
|
| + buffer_pool_ = new Buffer[buffer_pool_size_];
|
| + for (unsigned int i = 0; i < r_buffer.count; ++i) {
|
| + v4l2_buffer buffer = {};
|
| + buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + buffer.memory = V4L2_MEMORY_MMAP;
|
| + buffer.index = i;
|
| + buffer.length = 1;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QUERYBUF, &buffer)) < 0) {
|
| + DLOG(ERROR) << "Error querying status of a MMAP V4L2 buffer";
|
| + return false;
|
| + }
|
| +
|
| + // Some devices require mmap() to be called with both READ and WRITE.
|
| + // See http://crbug.com/178582.
|
| + buffer_pool_[i].start = mmap(NULL, buffer.length, PROT_READ | PROT_WRITE,
|
| + MAP_SHARED, device_fd_.get(), buffer.m.offset);
|
| + if (buffer_pool_[i].start == MAP_FAILED) {
|
| + DLOG(ERROR) << "Error mmmap()ing a V4L2 buffer into userspace";
|
| + return false;
|
| + }
|
| +
|
| + buffer_pool_[i].length = buffer.length;
|
| + // Enqueue the buffer in the drivers incoming queue.
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_QBUF, &buffer)) < 0) {
|
| + DLOG(ERROR)
|
| + << "Error enqueuing a V4L2 buffer back to the drivers incoming queue";
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool VideoCaptureDeviceLinux::V4L2CaptureDelegate::DeAllocateVideoBuffers() {
|
| + if (!buffer_pool_)
|
| + return true;
|
| +
|
| + for (int i = 0; i < buffer_pool_size_; ++i)
|
| + munmap(buffer_pool_[i].start, buffer_pool_[i].length);
|
| +
|
| + v4l2_requestbuffers r_buffer = {};
|
| + r_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
| + r_buffer.memory = V4L2_MEMORY_MMAP;
|
| + r_buffer.count = 0;
|
| + if (HANDLE_EINTR(ioctl(device_fd_.get(), VIDIOC_REQBUFS, &r_buffer)) < 0)
|
| + return false;
|
| +
|
| + delete [] buffer_pool_;
|
| + buffer_pool_ = NULL;
|
| + buffer_pool_size_ = 0;
|
| + return true;
|
| +}
|
| +
|
| +void VideoCaptureDeviceLinux::V4L2CaptureDelegate::SetErrorState(
|
| + const std::string& reason) {
|
| + DCHECK(v4l2_task_runner_->BelongsToCurrentThread());
|
| + is_capturing_ = false;
|
| + client_->OnError(reason);
|
| }
|
|
|
| } // namespace media
|
|
|