USBカメラからのFFMPEGキャプチャデータ


序文

FFMPEGを学習する過程で、直接ダウンロードできる画像データを取得する必要がありますが、処理の過程で、さまざまな形式のデータが必要です.たまたまUSBカメラがあり、USBから画像を取得するにはどうすればよいですかカメラ。Android では、基本的なデバイス管理は一般に v4l2 ドライバー フレームワークを介して管理されます. ここでは、v4l2 を使用して USB カメラを制御し、データ収集を実現しようとします.


1. v4l2 とは?

V4L2 は、Video for linux2 の略で、Linux のビデオ デバイス用のカーネル ドライバーです。Linux では、ビデオ デバイスはデバイス ファイルであり、通常のファイルのように読み書きできます. カメラは /dev/video* の下にあり、ビデオ デバイスが 1 つしかない場合は、通常は /dev/video0 です。一連のコールバック関数を使用してこれらの関数を実現する場合。カメラ周波数、フレームレート、ビデオ圧縮形式、画像パラメータなどを設定するのと同様に、プロセスは次のとおりです。
v4l2の利用の流れ

2. 具体的な実践

1. カメラの初期化

コードは次のとおりです (例)。

/**
 * @brief init_camera Initialize camera device properties
 * @param dev Equipment name
 * @return  
 */
int init_camera(const char* dev)
{
    
    
    fd = open(dev, O_RDWR);
    if(fd < 0){
    
    
        printf("open \"%s\" error\n", dev);
        return -1;
    }
 
	/**
	* Query device properties
	*/
    struct v4l2_capability cap;
    int ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
    if (ret < 0) {
    
    
        printf("VIDIOC_QUERYCAP error\n");
        return -1;
    }
 
	printf("Driver name : %s\n",cap.driver);
	printf("Device name : %s\n",cap.card);
	printf("Bus information : %s\n",cap.bus_info);
	printf("Drive version number : 0x%x\n",cap.version);
 
	if(cap.capabilities & V4L2_BUF_TYPE_VIDEO_CAPTURE){
    
     
			printf("Video capture device:\n");
			if(cap.capabilities & V4L2_CAP_STREAMING){
    
     
				printf("\tSupport video stream capture\n");
			}else{
    
    
				printf("Video stream capture is not supported\n");
			}
		}else {
    
    
			printf("Non video stream capture device\n");
			return -1;
		}
#if 1
		printf("\tQuery supported image formats:\n");
		struct v4l2_fmtdesc fmtdesc;
		fmtdesc.index=0;
		fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
		while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
		{
    
    
			printf("\t\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);
			fmtdesc.index++;
		}
#endif
		/*Format set*/
		//struct v4l2_format fmt = {0};
		fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//Camera buffer
		fmt.fmt.pix.width = 640;
		fmt.fmt.pix.height = 480;
		//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;//Pixel format (this parameter needs to be set according to the actual equipment situation)
		//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;	//OK
		fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;	//OK	YU12
		fmt.fmt.pix.field = V4L2_FIELD_NONE;
		if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)
		{
    
    
			printf("Format: %d failed\n",fmt.fmt.pix.pixelformat);
			return -1;
		}
		printf("Set the format of the acquired image V4L2_PIX_FMT_YUV420 success!\n");
		return 0;
}

2. メモリ マッピング

コードは次のとおりです (例)。

/**
 * @brief mmap_buffer Allocate user buffer memory and establish memory mapping
 * @return  
 */
int mmap_buffer()
{
    
    	
    printf("Allocate user space buffer\n");
	//struct BUFTYPE *usr_buf;
    usr_buf = (struct BUFTYPE *)calloc(buf_num, sizeof(struct BUFTYPE));
    if (!usr_buf) {
    
    
        printf("calloc \"frame buffer\" error : Out of memory\n");
        return -1;
    }
	
    printf("Allocate kernel buffers (including the number of frame buffers)\n");
    struct v4l2_requestbuffers req;
    req.count = buf_num;                    //num of frame buf
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //buf type of videocap
    req.memory = V4L2_MEMORY_MMAP;          //mem mmap type
    if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
    
    
        printf("VIDIOC_REQBUFS assignt kernel buffers failed \n");
        return -1;
    }


    /*mmap kernel buffers to user buffers*/
    printf("Mapping kernel buffer to user buffer\n");
    unsigned int i = 0;

	for(i = 0; i < buf_num; ++i)
	{
    
    
		/*query kernel buffers*/
		struct v4l2_buffer v4l2_buf;
		memset(&v4l2_buf, 0, sizeof(v4l2_buf));
		v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		v4l2_buf.memory = V4L2_MEMORY_MMAP;
		v4l2_buf.index = i;
		if(ioctl(fd , VIDIOC_QUERYBUF, &v4l2_buf) < 0)
		{
    
    
			printf("VIDIOC_QUERYBUF failed\n");
			return -1;
		}
	
		/* establish mmaping
		 * keep v4l2_buf.index and usr_buf.index the same
		 * when kernel buffer DQbug to queue,get kernel buffer index by user buffers index,
		 * then get the index data user want
		 */
		usr_buf[i].length = v4l2_buf.length;
		usr_buf[i].start = (char *)mmap(0, v4l2_buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, v4l2_buf.m.offset);
	
		if (MAP_FAILED == usr_buf[i].start)
		{
    
    //mmap failed
			printf("mmap failed: %d\n",i);
			return -1;
		}else
		{
    
    
			if (ioctl(fd, VIDIOC_QBUF, &v4l2_buf) < 0)
			{
    
     // mmap success,qbuf to queue
				printf("VIDIOC_QBUF failed\n");
				return -1;
			}
		}
	}
	printf("Mapping kernel buffer to user buffer success\n");
	return 0;
}

3.収集を開始する

コードは次のとおりです (例)。

/**
 * @brief stream_on 
 * @return 
 */
int stream_on()
{
    
    
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl(fd, VIDIOC_STREAMON, &type) < 0)
    {
    
    
        printf("VIDIOC_STREAMON failed\n");
        return -1;
    }
	printf("stream on success!\n");
    return 0;
}

4. ファイルに書き込む

コードは次のとおりです (例)。

/**
 * @brief write_frame read a frame
 * @return  return frame index,error for -1
 */
int write_frame(int index)
{
    
    
    int writenum = 0;
    struct v4l2_buffer v4l2_buf;
    v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    v4l2_buf.memory = V4L2_MEMORY_MMAP;
	v4l2_buf.index = index;
    if(ioctl(fd, VIDIOC_DQBUF, &v4l2_buf) < 0) // Kernel buffer out of queue
    {
    
    
        printf("VIDIOC_DQBUF failed, dropped frame\n");
        return -1;
    }
    printf("VIDIOC_DQBUF size[%d]\n",v4l2_buf.bytesused);

    /*
     * mmp kernel buffer to user buffer,get data by user buffer
     */
    char buffer[256];
    sprintf(buffer,"/data/V4L2_PIX_FMT_YVYU_%x-%d.yuv",fmt.fmt.pix.pixelformat,v4l2_buf.index);	//defined by fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    int file_fd = open(buffer,O_RDWR | O_CREAT); // didnot save this frame
    printf("open or creat a pic success\n");
    if(file_fd > 0)
    {
    
    
		//printf("data [%d] start:%s\n",v4l2_buf.index,usr_buf[v4l2_buf.index].start);
	    //printf("saving the %d frame image , size:%d\n",v4l2_buf.index,v4l2_buf.bytesused);
	    //itenum = write(file_fd,usr_buf[v4l2_buf.index].start,v4l2_buf.bytesused);
		printf("saving the [%d] frame image , size[%d]\n",v4l2_buf.index,v4l2_buf.bytesused);
		writenum = write(file_fd,usr_buf[v4l2_buf.index].start,v4l2_buf.bytesused);
	    printf("write %d byte\n",writenum);
	    if (0 < writenum )
	    {
    
    
	        printf("Write successful %d byte\n",writenum);
	    }
	    else
	    {
    
    
	        printf("Write failed%d\n",writenum);
	    }
	    close(file_fd);
    }
    else
    {
    
    
		printf("file_fd <= 0");
		return -1;
    }

    if (ioctl(fd, VIDIOC_QBUF, &v4l2_buf) < 0) //Buffer rejoining to queue
    {
    
    
        printf("VIDIOC_QBUF failed, dropped frame\n");
        return -1;
    }
    return v4l2_buf.index;
}

5. コード ストリームを閉じる

コードは次のとおりです (例)。

/**
 * @brief stream_off  
 * @return  
 */
int stream_off()
{
    
    	
    printf("Turn off video streaming\n");
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(ioctl(fd,VIDIOC_STREAMOFF,&type) == -1)
    {
    
    
        printf("Fail to ioctl 'VIDIOC_STREAMOFF'");
        return -1;
    }
    return 0;
}

6. アンマップ

コードは次のとおりです (例)。

/**
 * @brief unmap_buffer  
 * @return  
 */
int unmap_buffer()
{
    
    	
    printf("Unmap kernel buffer to user buffer\n");
    unsigned int i = 0;
    for(i = 0; i < buf_num; i++)
    {
    
    
        int ret = munmap(usr_buf[i].start, usr_buf[i].length);
        if (ret < 0)
        {
    
    
            printf("munmap failed\n");
            return -1;
        }
    }
    free(usr_buf); 
    return 0;
}

7. カメラの電源を切る

コードは次のとおりです (例)。

/**
 * @brief release_camera  
 */
void release_camera()
{
    
    
    printf("Turn off the device\n");
    close(fd);
}

8. メインプログラム

コードは次のとおりです (例)。

/**
 * @brief release_camera  
 */
void release_camera()
{
    
    
    printf("Turn off the device\n");
    close(fd);
}

int main(void)
{
    
    
    int ret = init_camera("/dev/video1");
    if(ret < 0){
    
    
        printf("init_camera error\n");
        return -1;
    }
#if 1
    ret = mmap_buffer();
    if(ret < 0){
    
    
        printf("mmap_buffer error\n");
        return -1;
    }

    ret = stream_on();
    if(ret < 0){
    
    
        printf("stream_on error\n");
        return -1;
    }
    int i=0;
    for(i=0;i<5;i++)
    {
    
    
        write_frame(i);
		encode_aframe(i);
    }

    ret = stream_off();
    if(ret < 0){
    
    
        printf("stream_off error\n");
        return -1;
    }

    ret = unmap_buffer();
    if(ret < 0){
    
    
        printf("unmap_buffer error\n");
        return -1;
    }
#endif
    release_camera();
    return 0;
}

要約する

これは主に、v4l2 を使用して USB カメラをキャプチャする方法を記録するためのものです. 途中で、エンコードに libx264 を使用する方法が散在していましたが、カードの所有者はまだデバッグ中であるため、後で記録することを忘れないでください.

おすすめ

転載: blog.csdn.net/qq_38750519/article/details/120922372