ffmpeg 采集摄像头yuv数据

本文讲述在linux下,如何使用ffmpeg采集摄像头yuv数据,并保存为文件。
分为4个部分进行讲解

  1. 需要的软硬件环境
  2. 使用ffmpeg命令采集yuv数据。
  3. 使用ffmpeg代码采集yuv数据。
  4. 查询摄像头支持采集数据的格式。

需要的软硬件环境

使用ffmpeg采集摄像头数据,需要具备两个条件:
首先,需要有一个摄像头。我这里使用的是USB摄像头,直接插在电脑主机之后。
其次,需要安装了ffmpeg。我这里是自己编译的ffmpeg。

使用ffmpeg命令采集yuv数据

首先,我们需要知道摄像头的位置。在linux下面,摄像头抽象成了一个设备文件**"/dev/video0"** ,这就是我们访问摄像头的位置。

其次,我们需要知道是通过什么驱动程序,来访问这个摄像头硬件的。linux下面,可以通过驱动video4linux2 来进行访问。

那么,使用如下ffmpeg命令,就可以采集yuv数据了。

ffmpeg -f video4linux2  -s 640x480 -i /dev/video0 out.avi

然后通过 ffplay来播放这个视频就可以。

ffplay out.avi

但是,我们需要采集的是yuv数据,还需要指定yuv的格式才行。这样,我们添加一个格式pix_fmt。

ffmpeg -f video4linux2 -s 640x480 -pix_fmt yuyv422 -i /dev/video0 out.yuv

我这里,摄像头是支持yuyv422格式的,所以我指定了pix_fmt为yuyv422,然后使用ffplay播放一下。

ffplay -s 640x480 -pix_fmt yuyv422 out.yuv

可以看到,播放正常。那就可以后续使用代码进行开发了。

使用ffmpeg代码采集yuv数据

使用ffmpeg代码,采集yuv数据,分成3步:

  1. 打开摄像头设备
  2. 读取yuv数据
  3. 保存文件

打开摄像头设备

打开设备,主要通过函数avformat_open_input 来进行,通过这个函数的参数,指定打开的设备路径“/dev/video0”,使用的驱动"video4linux2",以及指定相应的格式pix_fmt为yuyv422以及分辨率为640x480。

    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;
    char *devicename = "/dev/video0";
    avdevice_register_all();
    AVInputFormat *iformat = av_find_input_format("video4linux2");
    av_dict_set(&options,"video_size","640x480",0);
    av_dict_set(&options,"pixel_format","yuyv422", 0);
    avformat_open_input(&fmt_ctx, devicename, iformat, &options);
    avformat_close_input(&fmt_ctx);

读取yuv数据

读取yuv数据,主要是通过av_read_frame来进行的。

int ret = 0;
AVPacket pkt;
while((ret = av_read_frame(fmt_ctx, &pkt)) == 0) {
		av_log(NULL, AV_LOG_INFO,
               "packet size is %d(%p)\n",
               pkt.size, pkt.data);
		av_packet_unref(&pkt); //release pkt
}

保存文件

保存文件,直接通过fwrite函数写入即可。

    char *out = "out.yuv";
    FILE *outfile = fopen(out, "wb+");
	fwrite(pkt.data, 1, pkt.size, outfile); //614400
    fflush(outfile);
    fclose(outfile);

全部代码

#include 
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"


//@brief
//return
static AVFormatContext* open_dev(){
    int ret = 0;
    char errors[1024] = {0, };
    
    //ctx
    AVFormatContext *fmt_ctx = NULL;
    AVDictionary *options = NULL;
    
    //[[video device]:[audio device]]
    char *devicename = "/dev/video0";

    //register audio device
    avdevice_register_all();
    
    //get format
    AVInputFormat *iformat = av_find_input_format("video4linux2");
    
    av_dict_set(&options,"video_size","640x480",0);
    av_dict_set(&options,"pixel_format","yuyv422", 0);
    
    //open device
    if((ret = avformat_open_input(&fmt_ctx, devicename, iformat, &options)) < 0 ){
        av_strerror(ret, errors, 1024);
        fprintf(stderr, "Failed to open audio device, [%d]%s\n", ret, errors);
        return NULL;
    }
    
    return fmt_ctx;
}

void rec_video() {
    int ret = 0;
    AVFormatContext *fmt_ctx = NULL;
    int count = 0;

    //pakcet
    AVPacket pkt;
    
    //set log level
    av_log_set_level(AV_LOG_DEBUG);
    
    //create file
    char *out = "out.yuv";
    FILE *outfile = fopen(out, "wb+");
    
    //打开设备
    fmt_ctx = open_dev();

    //read data from device
    while((ret = av_read_frame(fmt_ctx, &pkt)) == 0 &&
          count++ < 100) {
        av_log(NULL, AV_LOG_INFO,
               "packet size is %d(%p)\n",
               pkt.size, pkt.data);
        
        fwrite(pkt.data, 1, pkt.size, outfile); //614400
        fflush(outfile);
        av_packet_unref(&pkt); //release pkt
    }
  
__ERROR:
    if(outfile){
        //close file
        fclose(outfile);
    }
    
    //close device and release ctx
    if(fmt_ctx) {
        avformat_close_input(&fmt_ctx);
    }

    av_log(NULL, AV_LOG_DEBUG, "finish!\n");
    return;
}


int main(int argc, char *argv[])
{
    rec_video();
    return 0;
}

使用命令gcc record_video.c -lavformat -lavutil -lavdevice -lavcodec -o record_video进行编译,然后运行**./record_video**,最后得到一个out.yuv。
然后使用命令

 ffplay -s 640x480 -pix_fmt yuyv422 out.yuv 

可以看到,正常播放,录制yuv数据成功。

查询摄像头支持的数据格式

v4l2有一个工具,可以查询摄像头支持的数据格式。我们先安装这个工具,使用如下命令。

sudo apt install v4l-utils

然后使用这个工具,查询我们的摄像头设备。

v4l2-ctl --list-devices

我这里列出了如下内容

USB2.0 Camera: USB2.0 Camera (usb-0000:00:14.0-8):
	/dev/video0

说明我这里,只有一个摄像头,然后访问地址为/dev/video0。然后查询一下/dev/video0支持的格式。

sudo v4l2-ctl -d /dev/video0 --list-formats

我这里列出的内容如下

ioctl: VIDIOC_ENUM_FMT
	Index       : 0
	Type        : Video Capture
	Pixel Format: 'YUYV'
	Name        : YUYV 4:2:2

就只有这一种,难怪,我想设置成nv12,怎么都不能输出数据。我这摄像头便宜,就只支持这种yuyv422的格式。

你可能感兴趣的:(ffmpeg)