2016-06-24 17 views
0

(Raspberry Piカメラの)V4L2デバイスのビデオをCに録画したい。 録画自体が機能し、ビデオをファイルに保存できます。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コマンドを実装しないでサポートしていない場合でも、コマンドを実行することができ、v4l2のデフォルト実装にルーティングされます。実際の変更はカメラ設定に適用されません。

+0

"dmesg"コマンドを実行すると、デバッグメッセージが表示されます。 Linuxカーネルのソースツリーでドライバのソースコードを入手できるはずです。VIDIOC_S_EXT_CTRLSを調べて、ドライバがコマンドで何をするかを調べる必要があります。 – user3843126

関連する問題