如何解决VIDIOC_S_FMT 给出错误但类型正确
在执行 ioctl(fd,VIdioC_S_FMT,&fmt)
时,我收到一个错误,指出 fmt 的类型错误。
我正在尝试将相机与谷歌珊瑚连接起来。但是,它与电路板没有任何 I2C 连接。因此,我使用带有 v4l2 的 videodev2 API 来编写我自己的“驱动程序”。由于没有 I2C 连接,我自己填写 v4l2_format 结构,为此查看 documentation。据说 VIdioC_G_FMT 将用它拥有的信息尽可能地填充结构,并使用 VIdioC_S_FMT 使用预填充的结构。因此,我为此特定部分的代码如下所示:
CLEAR(fmt); // set the format of the v4l2 video
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
if (-1 == xioctl(fd,VIdioC_G_FMT,&fmt))
errno_exit("VIdioC_G_FMT");
printf("fmt.fmt.pix.width = %d\n",fmt.fmt.pix.width);
printf("fmt.fmt.pix.pixelformat = %d\n",fmt.fmt.pix.pixelformat);
printf("Set RGB888\r\n");
fmt.fmt.pix.width = 640; //replace
fmt.fmt.pix.height = 483; //replace
fmt.fmt.pix.pixelformat = SDE_PIX_FMT_RGB_888; //replace
fmt.fmt.pix.field = V4L2_FIELD_ANY;
printf("fmt fields adjusted\n");
printf("fmt.type = %d\n",fmt.type);
if (-1 == xioctl(fd,&fmt)){
switch (errno) {
case EAGAIN:
printf("EAGAIN\n");
break;
case EINVAL:
printf("EINVAL,fmt.type field is invalid\n");
break;
case EBADR:
printf("EBADR\n");
break;
case EBUSY:
printf("EBUSY\n");
break;
/* fall through */
}
errno_exit("VIdioC_S_FMT");
}
我得到了错误:
EINVAL,fmt.type field is invalid
VIdioC_S_FMT error 22,Invalid argument
每次,即使类型填写正确。我不知道这是怎么回事。
任何帮助将不胜感激!
完整代码:
/*
* V4L2 video capture example
*
* This program can be used and distributed without restrictions.
*
* This program is provided with the V4L2 API
* see http://linuxtv.org/docs.PHP for more information
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <fcntl.h> /* low-level I/O */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#define CLEAR(x) memset(&(x),sizeof(x))
#define SDE_PIX_FMT_RGB_888 V4L2_PIX_FMT_RGB24 // from: https://android.googlesource.com/kernel/msm/+/android-7.1.0_r0.2/include/uapi/media/msm_sde_rotator.h
#ifndef V4L2_PIX_FMT_H264
#define V4L2_PIX_FMT_H264 v4l2_fourcc('H','2','6','4') /* H264 with start codes */
#endif
struct buffer {
void *start;
size_t length;
};
static char *dev_name;
static int fd = -1;
struct buffer *buffers;
static unsigned int n_buffers;
static int out_buf;
static int force_format;
static int frame_count = 200;
static int frame_number = 0;
static void errno_exit(const char *s)
{
fprintf(stderr,"%s error %d,%s\n",s,errno,strerror(errno));
exit(EXIT_FAILURE);
}
static int xioctl(int fh,int request,void *arg)
{
int r;
do {
r = ioctl(fh,request,arg);
} while (-1 == r && EINTR == errno);
return r;
}
static void process_image(const void *p,int size)
{
printf("processing image\n");
frame_number++;
char filename[15];
sprintf(filename,"frame-%d.raw",frame_number); // filename becomes frame-x.raw
FILE *fp=fopen(filename,"wb");
if (out_buf)
fwrite(p,size,1,fp); // write data to file fp
fflush(fp);
fclose(fp);
}
static int read_frame(void)
{
printf("reading frame\n");
struct v4l2_buffer buf;
unsigned int i;
/*
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd,VIdioC_DQBUF,&buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO,see spec.
/* fall through
default:
errno_exit("VIdioC_DQBUF");
}
}
assert(buf.index < n_buffers);
process_image(buffers[buf.index].start,buf.bytesused);
if (-1 == xioctl(fd,VIdioC_QBUF,&buf))
errno_exit("VIdioC_QBUF");
*/
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(fd,&buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO,see spec. */
/* fall through */
default:
errno_exit("VIdioC_DQBUF");
}
}
for (i = 0; i < n_buffers; ++i)
if (buf.m.userptr == (unsigned long)buffers[i].start
&& buf.length == buffers[i].length)
break;
assert(i < n_buffers);
process_image((void *)buf.m.userptr,buf.bytesused);
if (-1 == xioctl(fd,&buf))
errno_exit("VIdioC_QBUF");
return 1;
}
static void mainloop(void)
{
printf("mainloop\n");
unsigned int count;
count = frame_count;
while (count-- > 0) {
printf("count number = %d\n",count );
for (;;) {
fd_set fds;
struct timeval tv;
int r;
FD_ZERO(&fds); // clear file descriptor
FD_SET(fd,&fds); // set file descriptors to the descriptor fd
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1,&fds,NULL,&tv); // select uses a timeout,allows program to monitor file descriptors waiting untill files becomes "ready"
// returns the number of file descriptors changed. This maybe zero if timeout expires.
// probably watching reafds descriptor to change?
if (-1 == r) {
if (EINTR == errno)
continue;
errno_exit("select");
}
if (0 == r) {
fprintf(stderr,"select timeout\n");
exit(EXIT_FAILURE);
}
if (read_frame()) // if one of the descriptors is set,a frame can be read.
break;
/* EAGAIN - continue select loop. */
}
}
printf("mainloop ended\n");
}
static void stop_capturing(void)
{
printf("stop capturing\n");
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd,VIdioC_STREAMOFF,&type))
errno_exit("VIdioC_STREAMOFF");
printf("capturing stopped\n");
}
static void start_capturing(void)
{
printf("initiating capturing\n");
unsigned int i;
enum v4l2_buf_type type;
/*
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(fd,&buf))
errno_exit("VIdioC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd,VIdioC_STREAMON,&type)){
errno_exit("VIdioC_STREAMON");
}
*/
struct v4l2_format fmt1;
fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(fd,&fmt1);
printf("fmt1.fmt.pix.width = %d\n",fmt1.fmt.pix.width);
printf("fmt1.fmt.pix.pixelformat = %d\n",fmt1.fmt.pix.pixelformat);
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
printf("%d\n",i);
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = i;
buf.m.userptr = (unsigned long)buffers[i].start;
buf.length = buffers[i].length;
printf("length %d\n",buf.length);
if (-1 == xioctl(fd,&buf))
switch (errno) {
case EAGAIN:
printf("EAGAIN\n");
break;
case EINVAL:
printf("EINVAL\n");
break;
case EBADR:
printf("EBADR\n");
break;
case EBUSY:
printf("EBUSY\n");
break;
/* fall through */
}
errno_exit("VIdioC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd,&type))
errno_exit("VIdioC_STREAMON");
printf("capturing initiated\n");
}
static void uninit_device(void)
{
unsigned int i;
/*
for (i = 0; i < n_buffers; ++i){
if (-1 == munmap(buffers[i].start,buffers[i].length)){
errno_exit("munmap");
}
}
*/
for (i = 0; i < n_buffers; ++i)
free(buffers[i].start);
free(buffers);
}
static void init_mmap(void)
{
printf("initiating mmap buffer\n");
struct v4l2_requestbuffers req; //struct with details of the buffer to compose
CLEAR(req);
req.count = 2;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
printf("ioctl VIdioC_REQBUFS\n");
if (-1 == xioctl(fd,VIdioC_REQBUFS,&req)) { // initiate buffer
if (EINVAL == errno) {
printf("EINVAL\n");
fprintf(stderr,"%s does not support "
"memory mapping\n",dev_name);
exit(EXIT_FAILURE);
} else {
printf("other option\n");
errno_exit("VIdioC_REQBUFS");
}
}
printf("memory allocated\n");
if (req.count < 2) {
fprintf(stderr,"Insufficient buffer memory on %s\n",dev_name);
exit(EXIT_FAILURE);
}
buffers = calloc(req.count,sizeof(*buffers)); // make the amount of buffers available
if (!buffers) {
fprintf(stderr,"Out of memory\n");
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { // go through buffers and adjust struct in it
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == xioctl(fd,VIdioC_QUERYBUF,&buf))
errno_exit("VIdioC_QUERYBUF");
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap(NULL /* start anywhere */,buf.length,PROT_READ | PROT_WRITE /* required */,MAP_SHARED /* recommended */,fd,buf.m.offset);
if (MAP_Failed == buffers[n_buffers].start)
errno_exit("mmap");
}
printf("mmap buffer initiated\n");
}
static void init_userp(unsigned int buffer_size)
{
printf("initiating userpointer\n");
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(fd,&req)) {
if (EINVAL == errno) {
fprintf(stderr,"%s does not support "
"user pointer I/O\n",dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIdioC_REQBUFS");
}
}
buffers = calloc(4,sizeof(*buffers));
if (!buffers) {
fprintf(stderr,"Out of memory\n");
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
buffers[n_buffers].length = buffer_size;
buffers[n_buffers].start = malloc(buffer_size);
if (!buffers[n_buffers].start) {
fprintf(stderr,"Out of memory\n");
exit(EXIT_FAILURE);
}
}
}
static void init_device(void)
{
printf("initiating device\n");
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
unsigned int min;
if (-1 == xioctl(fd,VIdioC_QUERYCAP,&cap)) { // gets information about driver and harware capabilities
if (EINVAL == errno) { // driver is not compatible with specifications
fprintf(stderr,"%s is no V4L2 device\n",dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIdioC_QUERYCAP");
}
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr,"%s is no video capture device\n",dev_name);
exit(EXIT_FAILURE);
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf(stderr,"%s does not support streaming I/O\n",dev_name);
exit(EXIT_FAILURE);
}
/* Select video input,video standard and tune here. */
CLEAR(cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == xioctl(fd,VIdioC_CROPCAP,&cropcap)) { // used to get cropping limits,pixel aspects,... fill in type field and get all this information back
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */
if (-1 == xioctl(fd,VIdioC_S_CROP,&crop)) { // get cropping rectangle
switch (errno) {
case EINVAL:
printf("EINVAL in VIdioC_S_CROP\n");
/* Cropping not supported. */
break;
default:
printf("other error in VIdioC_S_CROP\n");
/* Errors ignored. */
break;
}
}
} else {
/* Errors ignored. */
}
CLEAR(fmt); // set the format of the v4l2 video
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
if (-1 == xioctl(fd,fmt.type field is invalid\n");
break;
case EBADR:
printf("EBADR\n");
break;
case EBUSY:
printf("EBUSY\n");
break;
/* fall through */
}
errno_exit("VIdioC_S_FMT");
}
/*
if (force_format) {
printf("Set RGB888\r\n");
fmt.fmt.pix.width = 640; //replace
fmt.fmt.pix.height = 483; //replace
fmt.fmt.pix.pixelformat = SDE_PIX_FMT_RGB_888; //replace
fmt.fmt.pix.field = V4L2_FIELD_ANY;
printf("fmt fields adjusted\n");
printf("fmt.type = %d\n",fmt.type);
if (-1 == xioctl(fd,&fmt)){
switch (errno) {
case EAGAIN:
printf("EAGAIN\n");
break;
case EINVAL:
printf("EINVAL,fmt.type field is invalid\n");
break;
case EBADR:
printf("EBADR\n");
break;
case EBUSY:
printf("EBUSY\n");
break;
// fall through
}
errno_exit("VIdioC_S_FMT");
}
// Note VIdioC_S_FMT may change width and height.
} else {
// Preserve original settings as set by v4l2-ctl for example
if (-1 == xioctl(fd,&fmt))
errno_exit("VIdioC_G_FMT");
}
*/
/* Buggy driver paranoia. */
min = fmt.fmt.pix.width * 2;
if (fmt.fmt.pix.bytesperline < min)
fmt.fmt.pix.bytesperline = min;
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (fmt.fmt.pix.sizeimage < min)
fmt.fmt.pix.sizeimage = min;
//init_mmap();
init_userp(fmt.fmt.pix.sizeimage);
printf("fmt.fmt.pix.width = %d\n",fmt.fmt.pix.pixelformat);
printf("device inititiated\n");
}
static void close_device(void)
{
printf("closing device\n");
if (-1 == close(fd))
errno_exit("close");
fd = -1;
printf("device closed\n");
}
/*
struct stat {
dev_t st_dev; ID of device containing file
ino_t st_ino; Inode number
mode_t st_mode; File type and mode
nlink_t st_nlink; Number of hard links
uid_t st_uid; User ID of owner
gid_t st_gid; Group ID of owner
dev_t st_rdev; Device ID (if special file)
off_t st_size; Total size,in bytes
blksize_t st_blksize; Block size for filesystem I/O
blkcnt_t st_blocks; Number of 512B blocks allocated
Since Linux 2.6,the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6,see NOTES.
struct timespec st_atim; Time of last access
struct timespec st_mtim; Time of last modification
struct timespec st_ctim; Time of last status change
#define st_atime st_atim.tv_sec Backward compatibility
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
*/
static void open_device(void)
{
printf("openening device\n");
struct stat st;
if (-1 == stat(dev_name,&st)) { // stat() returns info about file into struct
fprintf(stderr,"Cannot identify '%s': %d,dev_name,strerror(errno));
exit(EXIT_FAILURE);
}
if (!S_ISCHR(st.st_mode)) {
fprintf(stderr,"%s is no device\n",dev_name);
exit(EXIT_FAILURE);
}
fd = open(dev_name,O_RDWR /* required */ | O_NONBLOCK,0); // open the file dev/video0,returns a file descriptor
// if fd == -1,the file Could not be opened.
if (-1 == fd) {
fprintf(stderr,"Cannot open '%s': %d,strerror(errno));
exit(EXIT_FAILURE);
}
printf("device opened\n");
}
int main(int argc,char **argv)
{
printf("main begins\n");
dev_name = "/dev/video0";
for (;;) {
printf("back here\n");
break;
}
force_format = 1;
open_device();
init_device();
start_capturing();
mainloop();
stop_capturing();
uninit_device();
close_device();
fprintf(stderr,"\n");
return 0;
}
在终端中完整打印:
main begins
back here
openening device
device opened
initiating device
fmt.fmt.pix.width = 0
fmt.fmt.pix.pixelformat = 0
Set RGB888
fmt fields adjusted
fmt.type = 1
EINVAL,Invalid argument
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。