简体   繁体   English

如何正确设置V4L2中的扩展控件?

[英]How to set extended controls in V4L2 correctly?

I want to record a video from a V4L2 device (from the Raspberry Pi camera) in C. The recording itself works and I can save the video to a file. 我想在C中录制来自V4L2设备(来自Raspberry Pi摄像机)的视频。录制本身可以正常工作,我可以将视频保存到文件中。

However I need to change the bitrate of the video. 但是,我需要更改视频的比特率。 From the strace output of the v4l2-ctl --set-ctrl video_bitrate=10000000 command I know that the extended controls API of v4l2 is used to achieve this. 从v4l2-ctl --set-ctrl video_bitrate = 10000000命令的strace输出中,我知道v4l2的扩展控件API用于实现此目的。

Here's my code which doesn't work so far: 这是我目前无法使用的代码:

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>   //mmap
#include <fcntl.h>
#include <unistd.h>
#include <linux/videodev2.h>

using namespace std;

#define numbuffers 3

struct picturebuffer
{
   void *startadress;
   size_t length;
};

//array in which the buffer pointer are being stored
picturebuffer pb[numbuffers];

int main()
{
   //open camera
   int fd;
   fd = open("/dev/video0", O_RDWR);
   if(fd < 0)
   {
      cout << "error during opening the camera device!";
      cout.flush();
   }
   cout << "camera opened";

   //read capabilities
   struct v4l2_capability caps;
   if(ioctl(fd, VIDIOC_QUERYCAP, &caps) < 0)
   {
      cout << "error while reading the capabilities!";
      cout.flush();
   }
   cout << "Capabilities " << caps.capabilities << endl;
   //ToDo: check for required capabilities

   //set image data
   struct v4l2_format format;
   format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   format.fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
   format.fmt.pix.width = 1920;
   format.fmt.pix.height = 1080;
   if(ioctl(fd, VIDIOC_S_FMT, &format) < 0)
   {
      cout << "error in the image format";
   }
   cout << "Image properties set" << endl;
   //Todo: check if width and height fit together (VIDIOC_ENUM_FRAMESIZES)

   //set extended Controls
   struct v4l2_ext_controls ecs;
   struct v4l2_ext_control ec;
   memset(&ecs, 0, sizeof(ecs));
   memset(&ec, 0, sizeof(ec));
   ec.id = V4L2_CID_MPEG_VIDEO_BITRATE;
   ec.value = 10000000;
   ec.size = 0;
   ecs.controls = &ec;
   ecs.count = 1;
   ecs.ctrl_class = V4L2_CTRL_CLASS_MPEG;
   if(ioctl(fd, VIDIOC_S_EXT_CTRLS, &ecs) < 0)
   {
      cout << "error in extended controls bitrate";
      cout.flush();
   }

   //allocate buffer in the kernel
   struct v4l2_requestbuffers req;
   req.count = numbuffers;
   req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   req.memory = V4L2_MEMORY_MMAP;
   if(ioctl(fd, VIDIOC_REQBUFS, &req) < 0)
   {
      cout << "errro while allocating buffer";
      cout.flush();
   }
   cout << "number of buffers: " << req.count << endl;
   cout.flush();

   //map buffers into userspace
   for(int i=0; i<numbuffers; i++)
   {
      struct v4l2_buffer bufferinfo;
      memset(&bufferinfo, 0, sizeof(bufferinfo));
      bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      bufferinfo.memory = V4L2_MEMORY_MMAP;
      bufferinfo.index = i;
      if(ioctl(fd, VIDIOC_QUERYBUF, &bufferinfo) < 0)
      {
         cout << "error while querying bufferinfo";
         cout.flush();
      }
      pb[i].startadress = mmap(NULL, bufferinfo.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, bufferinfo.m.offset);
      pb[i].length = bufferinfo.length;
      if(pb[i].startadress == MAP_FAILED)
      {
         cout << "error during mmap" << endl;
      }
      memset(pb[i].startadress, 0, bufferinfo.length);
      cout << "size of buffer: " << bufferinfo.length << endl;
   }
   cout << "buffers mapped into userspace" << endl;
   cout.flush();

   //queue in the buffers
   for(int i=0; i<numbuffers; i++)
   {
      struct v4l2_buffer bufferinfo;
      memset(&bufferinfo, 0, sizeof(bufferinfo));
      bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      bufferinfo.memory = V4L2_MEMORY_MMAP;
      bufferinfo.index = i;
      if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
      {
         cout << "error while queueing the buffers in" << endl;
      }
   }

   //since that point the driver starts capturing the pics
   int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   if(ioctl(fd, VIDIOC_STREAMON, &type) < 0)
   {
      cout << "error while starting the stream" << endl;
   }

   int file;
   if((file = open("/home/pi/image.h264", O_WRONLY | O_CREAT, 0660)) < 0)
   {
      cout << "error while writing the file";
   }

   //loop for managing the pics
   for(int i=0; i<100; i++)
   {
      struct v4l2_buffer bufferinfo;
      memset(&bufferinfo, 0, sizeof(bufferinfo));
      bufferinfo.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      bufferinfo.memory = V4L2_MEMORY_MMAP;
      if(ioctl(fd, VIDIOC_DQBUF, &bufferinfo) < 0)
      {
         cout << "error while getting the buffer!" << endl;
      }

      //do anything with the pic
      char buf[pb[bufferinfo.index].length];
      memcpy(&buf, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);
      cout << bufferinfo.index << endl;
      cout.flush();

      //write picture into the file
      write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].length);

      if(ioctl(fd, VIDIOC_QBUF, &bufferinfo) < 0)
      {
         cout << "error while enqueuing the buffer" << endl;
      }
   }
   close(file);
   if(ioctl(fd, VIDIOC_STREAMOFF, &type) < 0)
   {
      cout << "error while stopping the stream" << endl;
   }

   //clean up
   for(int i=0; i<numbuffers; i++)
   {
      if(munmap(pb[i].startadress, pb[i].length) < 0)
      {
         cout << "error during unmap";
      }
   }

   //close camera file
   close(fd);
   cout << "!!!Hello World!!!" << endl;
   cout.flush();
   return 0;
}

The ioctl call seems to succeed, however my output file always has the same size as of 199,2 MB. ioctl调用似乎成功了,但是我的输出文件的大小始终等于199,2 MB。 Does someone know what´s wrong in the code ? 有人知道代码中有什么问题吗?

You need to check if the camera driver supports that IOCTL command. 您需要检查相机驱动程序是否支持该IOCTL命令。 If the driver doesn't support the IOCTL command by not implementing it, you still can execute the command and it is routed to v4l2 default implementation, no actual changes are applied to the camera setting 如果驱动程序通过不执行而不支持IOCTL命令,您仍然可以执行该命令并将其路由到v4l2默认实现,则不会对摄像机设置进行任何实际更改

Try to change the lines: 尝试更改行:

pb[bufferinfo.index].length pb [bufferinfo.index] .length

By: 通过:

pb[bufferinfo.index].bytesused

For example: 例如:

write(file, pb[bufferinfo.index].startadress, pb[bufferinfo.index].bytesused);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM