Ubuntu下使用ffmpeg调用设备摄像头采集视频,保存yuv文件并播放

Ubuntu下使用ffmpeg调用设备摄像头采集视频,保存yuv文件并播放

打开视频设备

AVFormatContext* open_dev()
{
    // 获取采集格式
    AVInputFormat *inputFmt = av_find_input_format("video4linux2"); // 视频

    int ret = 0;
    AVFormatContext *fmt_ctx = NULL;
    char *deviceName = "/dev/video0"; // 视频设备
    AVDictionary *options = NULL;

    av_dict_set(&options, "video_size", "640x480", 0);  // 为打开视频设备设置参数
//    av_dict_set(&options, "pixel_format", "yuyv422",0);
    // 打开设备
    ret = avformat_open_input(&fmt_ctx, deviceName, inputFmt, &options);

    char errors[1024] = {0};
    if (ret < 0)
    {
        av_strerror(ret, errors, 1024);
        printf("Failed to open audio device, [%d]%s\n", ret, errors);
        return NULL;
    }
    return fmt_ctx;
}

录制视频并保存文件

void MainWindow::rec_video()
{
    AVFormatContext *fmt_ctx = NULL;
    AVPacket packet;
    av_init_packet(&packet);
    int ret = 0;
    // 设置日志级别
    av_log_set_level(AV_LOG_DEBUG);
    // 注册设备
    avdevice_register_all();

    // 创建文件
    char *outPath = "/opt/document/vedio.yuv";   // 保存视频文件
    FILE *outFile = fopen(outPath, "wb+");
    if (!outFile)
    {
        goto __ERROR;
    }

    // 打开设备
    fmt_ctx = open_dev();
    if (!fmt_ctx)
    {
        goto __ERROR;
    }

    while ((ret = av_read_frame(fmt_ctx, &packet) == 0) && m_status)
    {
        av_log(NULL, AV_LOG_INFO, "Packet size: %d(%p)\n",
               packet.size, packet.data);

        // 写入文件
        fwrite(packet.data, 1, packet.size, outFile);
        fflush(outFile);

        // 释放packet空间
        av_packet_unref(&packet);
    }

__ERROR:

    // 关闭文件
    if (outFile)
    {
        fclose(outFile);
    }

    // 关闭设备,释放上下文空间
    if (fmt_ctx)
    {
        avformat_close_input(&fmt_ctx);
    }

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

下图为获取到的视频数据包大小:
在这里插入图片描述

av_read_frame阻塞问题:

采集视频时遇到了一个问题,就是程序执行到**while ((ret = av_read_frame(fmt_ctx, &packet) == 0) && m_status)**语句时会阻塞,程序一直卡在这个地方,没有返回,输出区没有packet大小,保存的文件大小为0字节。
因为我在虚拟机中连接了主机的摄像头,打开设备时摄像头也点亮了,所以我一直以为是代码有问题,尝试设置了回调、延时等等方法,都没有效果。最后我使用cheese调用摄像头,发现摄像头采集不到画面,我才发现是虚拟机设置的问题。
在这里插入图片描述
可以根据下拉列表具体内容选择,我这里改成了USB3.1。
然后再执行代码,很流畅的采集到了视频。
使用ffplay播放采集到的视频也正常。

ffplay -pix_fmt yuyv422 -s 640x480 vedio.yuv 

播放参数设置可以根据实际情况修改。
在这里插入图片描述

### 使用 FFmpeg 调用摄像头进行视频采集Ubuntu 下可以使用 `ffmpeg` 命令来调用设备摄像头采集视频。具体来说,可以通过指定 `-f video4linux2` 或者 `-f v4l2` 来访问 Linux 上的 V4L2 设备接口[^1]。 对于编码部分,如果希望采用 H.264 编码器,则可以在命令中加入 `-c:v libx264` 参数以指明这一点,最终将输出保存为 `.h264` 文件或者封装成其他容器格式如 MP4 等。 下面是一个简单的例子用于启动默认摄像头发射未压缩 YUV 流: ```bash ffmpeg -f v4l2 -i /dev/video0 output.yuv ``` 而当目标是获取经过硬件加速处理后的 h264 数据流时,可调整上述指令如下所示: ```bash ffmpeg -f v4l2 -input_format mjpeg -i /dev/video0 -vcodec libx264 -preset fast test.h264 ``` 此命令会尝试读取来自 `/dev/video0` 的 MJPEG 图像序列作为输入源,应用快速预设下的 x264 编码方案转换成低延迟模式下的 H.264 格式的比特流文件。 另外,在某些情况下可能还需要设置额外参数比如帧率 (`-r`) 和分辨率 (`-s width*height`) 以便更好地控制捕获过程中的图像质量与性能表现[^3]。 例如要限定每秒捕捉 30 幅画面且分辨率为 1920×1080 的高清视频片段,那么完整的命令应该是这样的形式: ```bash ffmpeg -f v4l2 -framerate 30 -video_size 1920x1080 -i /dev/video0 -c:v libx264 -preset veryfast out.mp4 ``` 值得注意的是不同型号的摄像头支持的功能有所差异,因此建议先通过查询设备属性了解其特性再做相应配置优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VectorAL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值