Все нижеперечисленное использует
#include <linux/videodev2.h>
#include <vector>
По сути, мне приходится передавать с компьютера камеры. ИСПОЛЬЗУЯ формат YUV, я грубо говорю new uint8_t [IMAGE_HEIGHT * IMAGE_WIDTH * 2] , который должен быть заполнен (поставлен в очередь).
Идея в том, что мне нужно сделать 5 кадров, каждый из которых указывает на uint8_t *.
std::vector<uint8_t*> v4l2_buffers;
Другой класс, называемый CameraStream, выделит буферы и вернет точку этому кадру, содержащему изображение.
Чтобы поставить в буфер приложения, задайте поле типа структуры v4l2_buffer к тому же типу буфера, который использовался ранее с типом struct v4l2_format и типом struct v4l2_requestbuffers. Приложения также должны установить поле индекса. Допустимые номера индексов варьируются от нуля до количества буферов, выделенных с помощью ioctl VIDIOC_REQBUFS (struct v4l2_requestbuffers count) минус один. Содержимое struct v4l2_buffer, возвращаемое ioctl VIDIOC_QUERYBUF ioctl, тоже подойдет. Когда буфер предназначен для вывода (типом является V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE или V4L2_BUF_TYPE_VBI_OUTPUT), приложения также должны инициализировать информацию об использованных байтах, поля и метки времени см. В разделах «Байт и метка времени»; Приложения также должны установить флаги на 0. Зарезервированные поля 2 и зарезервированные должны быть установлены на 0. При использовании многоплоскостного API поле m.planes должно содержать указатель пользовательского пространства на заполненный массив struct v4l2_plane и поле длины должен быть установлен на количество элементов в этом массиве. .Чтобы поставить в очередь приложения-указатели в буфере, установите для поля памяти значение V4L2_MEMORY_USERPTR, для поля m.userptr - адрес буфера, а для длины - его размер. Когда используется многоплоскостной API, вместо него должны использоваться члены m.userptr и length переданного массива struct v4l2_plane. Когда VIDIOC_QBUF вызывается с указателем на эту структуру, драйвер устанавливает флаг V4L2_BUF_FLAG_QUEUED и очищает флаги V4L2_BUF_FLAG_MAPPED и V4L2_BUF_FLAG_DONE в поле flags или возвращает код ошибки. Этот ioctl блокирует страницы памяти буфера в физической памяти, они не могут быть выгружены на диск. Буферы остаются заблокированными до тех пор, пока не будут сняты, до тех пор, пока ioctl VIDIOC_STREAMOFF или ioctl VIDIOC_REQBUFS не будет вызван, или пока устройство не будет закрыто.
/*
Allocate 5 buffers and form and abstraction to buffers with a continous loop of buffers.
CameraChannel must require a buffer from CameraStream class.
Pass that buffer to v4l2 to fill with frame data
*/
#include <cstdint>
#include <linux/videodev2.h>
#include <fcntl.h>
#include <iostream>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <vector>
#define FRAME_NUM 5
class CameraStream{
public:
CameraStream(int fd);
void allocateBuffer();
uint8_t *returnBufferAddress();
private:
int sfd;
unsigned int n_buffers;
v4l2_requestbuffers requestBuffers{0};
std::vector<uint8_t*> v4l2_buffers;
};
CameraStream. cpp
#include "CameraStream.h"
#include "Camera.h"
CameraStream::CameraStream(int fd):sfd(fd){
}
void CameraStream::allocateBuffer(){
/* This has to be the number of buffers I want to allocate in the device*/
/* Don't forget to change BUF_NUM or FRAME_NUM */
requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
requestBuffers.memory = V4L2_MEMORY_USERPTR;
if(-1 == xioctl(sfd,VIDIOC_REQBUFS,&requestBuffers)){
if(EINVAL == errno) {
perror("Device does not support user pointer\n");
} else {
perror("VIDIOC_REQBUFS");
}
}
/*
Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing)
or filled (output) buffer in the driver’s incoming queue.
The semantics depend on the selected I/O method.
To enqueue a buffer applications set the type field of a struct v4l2_buffer
to the same buffer type as was previously used with struct v4l2_format
type and struct v4l2_requestbuffers type. Applications must also set
the index field. Valid index numbers range from zero to the number of
buffers allocated with ioctl VIDIOC_REQBUFS (struct v4l2_requestbuffers
count) minus one. The contents of the struct v4l2_buffer returned by a
ioctl VIDIOC_QUERYBUF ioctl will do as well. When the buffer is intended
for output (type is V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, or V4L2_BUF_TYPE_VBI_OUTPUT)
applications must also initialize the bytesused, field and
timestamp fields, see Buffers for details.
Applications must also set flags to 0.
The reserved2 and reserved fields must be set to 0.
When using the multi-planar API, the m.planes field
must contain a userspace pointer to a filled-in array
of struct v4l2_plane and the
length field must be set to the number of elements in that array.
*/
for(int i = 0;i < FRAME_NUM ; i++){
// v4l2_buffers.push_back(uint8_t[IMAGE_HEIGHT*IMAGE_WIDTH*2]);
v4l2_buffers.push_back(new uint8_t[IMAGE_HEIGHT*IMAGE_WIDTH*2]);
}
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.m.userptr = (unsigned long)&v4l2_buffers[0];
buf.index = 0;
buf.length = 1;
if(xioctl(sfd,VIDIOC_QBUF,&buf) == -1){
perror("VIDIOC_QBUF");
}
/*
This ioctl is part of the streaming I/O method.
It can be used to query the status of a buffer at any time
after buffers have been allocated with the ioctl VIDIOC_REQBUFS ioctl.
*/
//struct v4l2_buffer buf;
//for(int j = 0;j < IMAGE_HEIGHT*IMAGE_WIDTH*2;j++){
//buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//buf.index = j;
//if(xioctl(sfd,VIDIOC_QUERYBUF,&buf) == -1){
// perror("VIDIOC_QUERYBUF");
// }
//}
/*
v4l2_buffers.resize(BUF_NUM,std::vector<uint8_t*>(IMAGE_WIDTH*IMAGE_HEIGHT*2));
for(auto &frame:v4l2_buffers){
int c = 0;
for(auto& buffer:frame){
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = c++;
buf.m.userptr = (unsigned long)&buffer;
buf.length = sizeof(buffer);
if(-1 == xioctl(sfd,VIDIOC_QBUF,&buf))
perror("VIDIOC_QBUF");
}
}
*/
/*
memset(&(requestBuffers),0,sizeof(requestBuffers));
requestBuffers.count = BUF_NUM;
requestBuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
requestBuffers.memory = V4L2_MEMORY_USERPTR;
if(-1 == xioctl(sfd,VIDIOC_REQBUFS,&requestBuffers)){
if(EINVAL == errno){
perror("Device does not support user pointer\n");
}else{
perror("VIDIOC_REQBUFS");
}
}
struct v4l2_buffer buf;
for(n_buffers = 0;n_buffers < BUF_NUM;++n_buffers){
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.index = n_buffers;
if(xioctl(sfd, VIDIOC_QUERYBUF, &buf) == -1){
perror("VIDIOC_QUERYBUF");
}
//*Create the buffer
}
*/
}
main . cpp содержит класс Camera, который просто является начальным классом
#include <iostream>
#include "Camera.h"
#include "CameraStream.h"
int main(){
char *device = "/dev/video0";
Camera c(device);
c.open();
c.showCapabilities();
c.config(V4L2_PIX_FMT_YUYV);
CameraStream cam(c.getFd());
cam.allocateBuffer();
return 0;
}
Следующая ошибка отображается в выводе моего терминала.
open
This device has capabilities
Device does support this format, VIDIOC_S_FMT: Success
VIDIOC_QBUF: Device or resource busy
Внимание! напрямую смешивать запросы с очередями. EBUSY будет возвращен, если первый буфер был поставлен в очередь напрямую, а затем приложение пытается поставить в очередь запрос, или наоборот. После закрытия дескриптора файла, вызова VIDIOC_STREAMOFF или вызова ioctl VIDIOC_REQBUFS проверка для этого будет сброшена. Для устройств памяти в память вы можете указывать request_fd только для выходных буферов, а не для буферов захвата. Попытка указать это для буфера захвата приведет к ошибке EBADR.