blob: 97a065ca74e574743df66fdd76ba9cf130cc8d2a [file] [log] [blame]
/*
* Copyright (c) 2011 The WebM 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.
*
* Author: sgammon@google.com (Stacey Gammon)
*/
#include <errno.h>
#include <fcntl.h> // for O_RDWR and O_NONBLOC
#include <string.h> // for memset
#include <sys/ioctl.h>
#include <sys/mman.h> // for mmap
#include "logger.h"
#include "planeconverter.h"
#include "videocapturerother.h"
void VideoCapturerOther::StartCapture() {
FailOnNegative(fd_ = open("/dev/video0", O_RDWR | O_NONBLOCK),
"Failed to open video file descriptor");
SetCapabilities();
InitFormat();
SetStreamParameters();
InitRequestBuffers();
MapAndQueueBuffers();
// Start streaming.
FailOnNegative(ioctl(fd_, VIDIOC_STREAMON, &kVideoCaptureType),
"Failed on ioctl with VIDIOC_STREAMON");
}
void VideoCapturerOther::InitFormat() {
struct v4l2_format fmt;
memset(&fmt, 0, sizeof(struct v4l2_format));
fmt.type = kVideoCaptureType;
fmt.fmt.pix.width = config_.display_width();
fmt.fmt.pix.height = config_.display_height();
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
FailOnNegative(ioctl(fd_, VIDIOC_S_FMT, &fmt),
"ioctl VIDIOC_S_FMT failed");
}
void VideoCapturerOther::InitRequestBuffers() {
struct v4l2_requestbuffers rb;
memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
rb.count = kMaxBufferCount;
rb.type = kVideoCaptureType;
rb.memory = kVideoMemoryMMap;
FailOnNonZero(ioctl(fd_, VIDIOC_REQBUFS, &rb),
"Initializing request buffers failed.");
}
void VideoCapturerOther::SetCapabilities() {
struct v4l2_capability capability;
memset(&capability, 0, sizeof(struct v4l2_capability));
FailOnNegative(ioctl(fd_, VIDIOC_QUERYCAP, &capability),
"ioctl with VIDIOC_QUERYCAP failed");
}
void VideoCapturerOther::SetStreamParameters() {
struct v4l2_streamparm setfps;
memset(&setfps, 0, sizeof(struct v4l2_streamparm));
setfps.type = kVideoCaptureType;
setfps.parm.capture.timeperframe.numerator = 1;
setfps.parm.capture.timeperframe.denominator = config_.capture_frame_rate();
FailOnNonZero(ioctl(fd_, VIDIOC_S_PARM, &setfps),
"ioctl with VIDIOC_S_PARAM failed");
}
void VideoCapturerOther::MapAndQueueBuffers() {
struct v4l2_buffer buf;
for (int i = 0; i < kMaxBufferCount; i++) {
memset(&buf, 0, sizeof(struct v4l2_buffer));
buf.index = i;
buf.type = kVideoCaptureType;
buf.memory = kVideoMemoryMMap;
FailOnNegative(ioctl(fd_, VIDIOC_QUERYBUF, &buf),
"ioctl failed on VIDIOC_QUERYBUF");
mem_[i] = mmap(0 , buf.length, PROT_READ, MAP_SHARED, fd_, buf.m.offset);
MaybeCleanUpAndFail(mem_[i] == MAP_FAILED, "Failed while mapping buffers");
FailOnNegative(ioctl(fd_, VIDIOC_QBUF, &buf),
"ioctl with VIDIOC_QBUF failed");
}
}
bool VideoCapturerOther::BufferHasFrame() {
if (UserEnteredKey()) {
CleanUp();
return false;
}
struct v4l2_buffer buf;
buf.type = kVideoCaptureType;
buf.memory = kVideoMemoryMMap;
// Get a frame if we can.
if (ioctl(fd_, VIDIOC_DQBUF, &buf) < 0) {
MaybeCleanUpAndFail(errno != EAGAIN, "Failed to grab buffer");
return false;
}
if (buf.bytesused > 0) {
PlaneConverter::YuyToYv12(raw_->img_data, (char *) mem_[buf.index],
raw_->d_w, raw_->d_h);
}
MaybeCleanUpAndFail(ioctl(fd_, VIDIOC_QBUF, &buf) < 0,
"Failed putting buffer back");
buffer_seconds_ = TimeInSeconds();
return buffer_seconds_ > 0;
}
void VideoCapturerOther::CleanUp() {
if (ioctl(fd_, VIDIOC_STREAMOFF, &kVideoCaptureType)) {
LOG("Turning stream off failed.");
}
close(fd_);
finished_ = true;
}