2016-06-24 2 views
0

C에서 라스베리 파이 카메라의 V4L2 장치로 비디오를 녹화하고 싶습니다. 녹음 자체가 작동하며 비디오를 파일로 저장할 수 있습니다.V4L2의 확장 제어를 올바르게 설정하는 방법은 무엇입니까?

그러나 비디오의 비트 전송률을 변경해야합니다. v4l2-ctl -set-ctrl video_bitrate = 10000000 명령의 strace 출력에서 ​​v4l2의 확장 제어 API가이를 수행하는 데 사용됨을 알고 있습니다. 그러나 내 출력 파일은 항상 199,2 MB의 같은 크기를 가지고,

#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; 
} 

ioctl 시스템 호출이 성공하는 것 같다

여기에 지금까지 작동하지 않습니다 내 코드입니다. 누군가 코드에서 무엇이 잘못되었는지 알고 있습니까?

답변

0

카메라 드라이버가 IOCTL 명령을 지원하는지 확인해야합니다. 드라이버가 IOCTL 명령을 구현하지 않아도 IOCTL 명령을 지원하지 않으면 여전히 명령을 실행할 수 있으며 v4l2 기본 구현으로 라우팅됩니다. 실제 설정은 카메라 설정에 적용되지 않습니다.

+0

"dmesg"를 사용하여 명령을 실행할 때 모든 디버그 메시지가 출력됩니다. 당신은 리눅스 커널 소스 트리에서 드라이버의 소스 코드를 얻을 수 있어야한다. VIDIOC_S_EXT_CTRLS를보고 드라이버가 명령으로 무엇을하는지 보라. – user3843126

관련 문제