音视频开发—V4L2介绍,FFmpeg 打开摄像头输出yuv文件

实验平台:Ubuntu20.04

摄像头:1080P 监控摄像头,采用V4L2驱动框架

文章目录

    • 1.V4L2相关介绍
      • 1.1. 基本概念
      • 1.2. 主要功能
      • 1.3. V4L2驱动框架
      • 1.4. 主要组件
      • 1.5. 使用V4L2的应用
      • 1.6. 常用V4L2工具
    • 2.ffmpeg命令实现打开摄像头输出yuv文件
    • 3.使用C语言编程实现
    • 4.注意事项
      • 4.1Packet 和 Frame 的区别
      • 4.2为什么读取摄像头时使用 packet而不是 frame?

1.V4L2相关介绍

Video4Linux2(V4L2)是Linux内核中用于视频设备的一个API,旨在提供对视频捕捉、输出和处理设备的支持。它是Video4Linux(V4L)的继任者,具有更强的功能和更好的设计。以下是V4L2的详细介绍:

1.1. 基本概念

  • API: V4L2提供了一个标准的应用程序编程接口(API),使开发者能够在用户空间与视频设备进行交互。
  • 设备文件: 在Linux系统中,视频设备通常表示为 /dev/video0/dev/video1 等设备文件。

1.2. 主要功能

  • 视频捕捉: 从摄像头或其他视频输入设备捕获视频帧。
  • 视频输出: 将视频数据输出到显示设备或其他输出目标。
  • 视频流: 支持视频流的处理和传输,包括实时视频流的捕获和播放。
  • 图像处理: 提供基本的图像处理功能,如缩放、色彩转换等。

1.3. V4L2驱动框架

  • 驱动层: V4L2驱动程序位于内核空间,负责与硬件进行交互,控制视频设备的操作。
  • 用户空间API: 提供给应用程序使用的系统调用接口,如 ioctl 系列函数,用于配置和控制视频设备。

1.4. 主要组件

  • 设备节点: 在 /dev 目录下创建的设备文件,用于用户空间程序访问视频设备。
  • 控制接口: 通过 ioctl 函数设置和获取设备参数,如分辨率、帧率、视频格式等。
  • 缓冲区管理: 支持多种缓冲区管理模式,包括内存映射(mmap)、用户指针(user pointer)和DMA缓冲区(DMABUF)。
  • 格式转换: 支持多种视频格式,如YUV、RGB、MJPEG、H.264等,并提供格式转换功能。

1.5. 使用V4L2的应用

  • 视频采集应用: 使用V4L2 API开发的视频捕捉应用程序,如网络摄像头软件、视频录制软件等。
  • 多媒体框架: GStreamer、FFmpeg等多媒体框架支持V4L2,可以使用这些框架方便地进行视频处理和传输。
  • 嵌入式系统: 在嵌入式Linux系统中,V4L2广泛用于摄像头、视频采集卡等设备的驱动开发。

1.6. 常用V4L2工具

  • v4l2-ctl: 一个命令行工具,用于控制和调试V4L2设备。可以查询设备信息、设置参数、捕获视频帧等。
    v4l2-ctl --list-formats-ext  # 列出设备支持的所有格式
    v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=H264  # 设置视频格式
    v4l2-ctl --stream-mmap --stream-count=100 --stream-to=output.raw  # 捕获视频流
    

比如可以查看本次实验的摄像头的相关参数

marxist@ubuntu:~/Desktop/audio_test/build$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
	Type: Video Capture

	[0]: 'MJPG' (Motion-JPEG, compressed)
		Size: Discrete 1920x1080
			Interval: Discrete 0.033s (30.000 fps)
		Size: Discrete 640x480
			Interval: Discrete 0.008s (120.101 fps)
			Interval: Discrete 0.011s (90.000 fps)
			Interval: Discrete 0.017s (60.500 fps)
			Interval: Discrete 0.033s (30.200 fps)
		Size: Discrete 1280x720
			Interval: Discrete 0.017s (60.000 fps)
			Interval: Discrete 0.033s (30.500 fps)
		Size: Discrete 1024x768
			Interval: Discrete 0.033s (30.000 fps)
		Size: Discrete 800x600
			Interval: Discrete 0.017s (60.000 fps)
		Size: Discrete 1280x1024
			Interval: Discrete 0.033s (30.000 fps)
		Size: Discrete 320x240
			Interval: Discrete 0.008s (120.101 fps)
	[1]: 'YUYV' (YUYV 4:2:2)
		Size: Discrete 1920x1080
			Interval: Discrete 0.167s (6.000 fps)
		Size: Discrete 640x480
			Interval: Discrete 0.033s (30.000 fps)
		Size: Discrete 1280x720
			Interval: Discrete 0.111s (9.000 fps)
		Size: Discrete 1024x768
			Interval: Discrete 0.167s (6.000 fps)
		Size: Discrete 800x600
			Interval: Discrete 0.050s (20.000 fps)
		Size: Discrete 1280x1024
			Interval: Discrete 0.167s (6.000 fps)
		Size: Discrete 320x240
			Interval: Discrete 0.033s (30.000 fps)

由上述可知,摄像头一共支持两种格式,一是MJPG格式,已经由硬件压缩好的一种格式,一种就是常见的YUV422格式,YUV同样支持多种分辨率格式。得知这些参数之后,方便编程实现录制输出工作。

2.ffmpeg命令实现打开摄像头输出yuv文件

命令示例:

ffmpeg -f v4l2 -framerate 9 -video_size 1280x720 -pixel_format yuyv422 -i /dev/video0 -c:v rawvideo -pix_fmt yuv420p output.yuv

参数解释:

-f v4l2: 指定输入格式为V4L2(Video4Linux2)。

-framerate 9: 设置帧率为9fps。

-video_size 1280x720: 设置视频分辨率为1280x720(720p)。

-pixel_format yuyv422: 指定像素格式为YUYV422。

-i /dev/video0: 指定输入设备为 /dev/video0

-c:v rawvideo: 指定视频编码器为原始视频(不压缩)。

output.yuv: 指定输出文件名为 output.yuv

播放示例:

注意:需要指定格式和分辨率,原始的数据文件并不包含这些信息,需要手动指定才能播放。

ffplay -pix_fmt yuyv422 -s 1280*720 output.yuv 

效果图:

在这里插入图片描述

此时正常解析出来yuv画面。

3.使用C语言编程实现

主要流程较为简单,如下所示:

在这里插入图片描述

完整代码实现:

extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}
#include <iostream>
using namespace std;
#define OUTPUT_FILE "output.yuv"
#define CAMERA_DEVICE "/dev/video0"
AVFormatContext *format_ctx = NULL;
AVCodecContext *codec_ctx = NULL;
AVCodec *codec = NULL;
AVPacket packet ;
AVFrame *frame = NULL;
FILE *output_file = NULL;
AVInputFormat *input_format = NULL;
AVDictionary *options; //摄像头相关参数
int video_stream_index = -1;

int open_v4l2_cam()
{
    input_format = av_find_input_format("v4l2");

    if (!input_format)
    {
        fprintf(stderr, "Could not find input format 'v4l2'\n");
        return -1;
    }

    // 摄像头支持多种参数,因此使用option 指定参数 最大支持到9帧
    av_dict_set(&options, "video_size", "1280*720", 0);
    av_dict_set(&options, "framerate", "9", 0);
    av_dict_set(&options, "input_format", "yuyv422", 0);
    int ret = avformat_open_input(&format_ctx, CAMERA_DEVICE, input_format, &options);
    if (ret != 0)
    {
        cerr << "open input device fail" << endl;
        return -1;
    }
    ret = avformat_find_stream_info(format_ctx, NULL);
    if (ret < 0)
    {
        cerr << "findding stream info" << endl;
        return -1;
    }
    video_stream_index = -1;
    // 查找视频流
    for (size_t i = 0; i < format_ctx->nb_streams; i++)
    {
        /* code */
        if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            video_stream_index = i;
            break;
        }
    }
    if (video_stream_index == -1)
    {
        cerr << "no found video_steam" << endl;
        return -1;
    }
    return 0;
}
int init_codec_env()
{
    // 分配帧和数据包
    frame = av_frame_alloc();
    av_init_packet(&packet);
    // 准备写入文件
    output_file = fopen(OUTPUT_FILE, "wb");
    if (!output_file)
    {
        fprintf(stderr, "Error opening output file\n");
        return -1;
    }
}

void start_ouput_data()
{
    // 读取视频帧并保存为YUV 文件,
    cout << "start record" << endl;
    while (av_read_frame(format_ctx, &packet) >= 0)
    {
        if (packet.stream_index == video_stream_index)
        {
            fwrite(packet.data, 1, packet.size, output_file);
        }
        av_packet_unref(&packet);
    }
}
int main()
{

    avdevice_register_all(); // Ensure that device library is registered

    int ret = open_v4l2_cam();
    if (ret < 0)
    {
        cerr << "open cam fail !" << endl;
        return -1;
    }
    ret = init_codec_env();
    start_ouput_data();
    // 释放资源
    fclose(output_file);
    av_dict_free(&options);
    avformat_close_input(&format_ctx);
    return 0;
}

输出的yuv文件,为没有被编码的原始的数据,需要指定参数才能播放

效果如图:

在这里插入图片描述

4.注意事项

4.1Packet 和 Frame 的区别

  1. Packet(数据包):
    • 一般是指编码后的数据包(如H.264、H.265等编码格式的压缩数据)。
    • 包含元数据和编码数据。
    • 是数据流中的最小单位,可以包含一个完整帧或部分帧的数据。
  2. Frame(帧):
    • 是原始数据的表现形式,未经过编码压缩的原始视频或音频数据。
    • 在视频处理中,一个帧通常是一个完整的视频画面。
    • 在FFmpeg中,帧(AVFrame)是解码后的原始数据或编码前的原始数据。

4.2为什么读取摄像头时使用 packet而不是 frame?

当你通过FFmpeg读取视频数据时,即使没有显式地进行编码,FFmpeg也将视频数据封装在 AVPacket 中。原因如下:

  1. 数据流处理:
    • FFmpeg通过 av_read_frame 函数读取数据流,无论数据是否已经编码,读取到的数据都封装在 AVPacket 结构中。这是因为 AVPacket 是用于传输解码器或编码器之间的数据单位。
  2. 输入格式的处理:
    • 当使用 av_read_frame 从输入设备(如摄像头)读取数据时,FFmpeg将摄像头的原始数据作为 AVPacket 进行处理。这个 AVPacket 包含了从设备获取的原始数据块,即使这些数据是未压缩的。
  3. 统一接口:
    • av_read_frame 提供了一个统一的接口,用于处理各种输入数据流(文件、网络流、设备捕获)。这种设计简化了处理过程,不需要为不同的数据源提供不同的读取机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/671589.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文献阅读:GCNG:用于从空间转录组数据推断基因相互作用的图卷积网络

文献介绍 「文献题目」 GCNG: graph convolutional networks for inferring gene interaction from spatial transcriptomics data 「研究团队」 Ziv Bar-Joseph&#xff08;美国卡内基梅隆大学&#xff09; 「发表时间」 2020-12-10 「发表期刊」 Genome Biology 「影响因子…

一文搞懂分布式事务Seta-AT模式实现原理

分布式事务概念 分布式事务&#xff08;Distributed Transaction&#xff09; 是指在分布式系统中&#xff0c;涉及多个数据库、服务、消息队列等资源&#xff0c;并且需要保证这些资源上的操作要么全部成功提交&#xff0c;要么全部失败回滚的一种机制。在分布式系统中&#…

极简网络用户手册(1)

极简网络系统处理流程 模块位置&#xff1a;参数平台--专题分析--极简网络分析 步骤&#xff1a; 步骤一&#xff1a;创建精细化场景策略 步骤二&#xff1a;创建任务&#xff0c;主要选择策略&#xff08;包括√配置和距离配置&#xff09;和需要处理的小区清单&#xff08;源…

vulhub中Nexus Repository Manager 3 未授权目录穿越漏洞(CVE-2024-4956)

Nexus Repository Manager 3 是一款软件仓库&#xff0c;可以用来存储和分发Maven、NuGET等软件源仓库。 其3.68.0及之前版本中&#xff0c;存在一处目录穿越漏洞。攻击者可以利用该漏洞读取服务器上任意文件。 环境启动后&#xff0c;访问http://your-ip:8081即可看到Nexus的…

德克萨斯大学奥斯汀分校自然语言处理硕士课程汉化版(第四周) - 语言建模

语言建模 1. 统计语言模型2. N-gram语言建模 2.1. N-gram语言模型中的平滑处理 3. 语言模型评估4. 神经语言模型5. 循环神经网络 5.1. Vanilla RNN5.2. LSTM 1. 统计语言模型 统计语言模型旨在量化自然语言文本中序列的概率分布&#xff0c;即计算一个词序列&#xff08;如一…

【记忆化搜索】2318. 不同骰子序列的数目

本文涉及知识点 记忆化搜索 LeetCode 2318. 不同骰子序列的数目 给你一个整数 n 。你需要掷一个 6 面的骰子 n 次。请你在满足以下要求的前提下&#xff0c;求出 不同 骰子序列的数目&#xff1a; 序列中任意 相邻 数字的 最大公约数 为 1 。 序列中 相等 的值之间&#xff…

重庆耶非凡科技有限公司的选品师项目加盟靠谱吗?

在当今电子商务的浪潮中&#xff0c;选品师的角色愈发重要。而重庆耶非凡科技有限公司以其独特的选品师项目&#xff0c;在行业内引起了广泛关注。对于想要加盟该项目的人来说&#xff0c;项目的靠谱性无疑是首要考虑的问题。 首先&#xff0c;我们来看看耶非凡科技有限公司的背…

图解 IPv6 多播范围

1、 IPv6 多播范围 2、从单播地址生成请求节点多播地址 3、已分配的多播地址

Day04 左侧菜单导航实现

一.点击左侧菜单导航到对应的View页面 1.首先在MyToDo项目中,创建出左侧菜单所有的View(视图)及对应的ViewModel(视图逻辑处理类) ViewViewModel首页IndexViewIndexViewModel待办事项ToDoViewToDoViewModel忘备录MemoViewMemoViewModel设置SettingsViewSettingsViewModel

制作一个简单HTML旅游网站(HTML+CSS+JS)云南旅游网页设计与实现5个页面

一、&#x1f468;‍&#x1f393;网站题目 旅游&#xff0c;当地特色&#xff0c;历史文化&#xff0c;特色小吃等网站的设计与制作。 二、✍️网站描述 云南旅游主题的网页 一共七个个页面 - 旅游网页使用html css js制作 有banana图 - 页面可以相互跳转 包含表单 三级页面…

XFeat:速度精度远超superpoint的轻量级图像匹配算法

代码地址&#xff1a;https://github.com/verlab/accelerated_features?tabreadme-ov-file 论文地址&#xff1a;2404.19174 (arxiv.org) XFeat (Accelerated Features)重新审视了卷积神经网络中用于检测、提取和匹配局部特征的基本设计选择。该模型满足了对适用于资源有限设备…

sqlite基本操作

简介 文章目录 简介1.数据库的安装2.数据库命令&#xff1a;API&#xff0c;创建表单代码 csprintf&#xff08;&#xff09;getchar和scanf&#xff08;&#xff09; 1.数据库的安装 sudo dpkg -i *.deb这个报错表明出现依赖问题 用这个命令后再试试sudo apt --fix-broken in…

Nocobase快速上手 - 开发第一个插件

在前面的几篇博文中&#xff0c;记录了在Nocobase中配置collection和界面&#xff0c;这篇文章开始插件的开发。插件可以扩展Nocobase的业务能力&#xff0c;解锁更强大的功能。 环境搭建 创建插件需要配置nocobase的开发环境&#xff0c;笔者采用的是clone 官方代码repo的方…

【Centos7】解决 CentOS 7 中出现 “xx: command not found“ 错误的全面指南

【Centos7】初探xx:command not found解决方案 大家好 我是寸铁&#x1f44a; 【Centos7】解决 CentOS 7 中出现 “xx: command not found” 错误的全面指南✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 经常有小伙伴问我&#xff0c;xx:command not found怎么办&#xff1…

GPT-4o如何重塑AI未来!

如何评价GPT-4o? 简介&#xff1a;最近&#xff0c;GPT-4o横空出世。对GPT-4o这一人工智能技术进行评价&#xff0c;包括版本间的对比分析、GPT-4o的技术能力以及个人感受等。 GPT-4o似乎是一个针对GPT-4模型进行优化的版本&#xff0c;它在性能、准确性、资源效率以及安全和…

http请求方法get和post的区别

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 目录 关于http请求方法get和post的区别真正区别存在问题的区别 关于http请求方法get和post的区别 真正区别 实际上二者差异不大,在http里面,使用get的场景,使用post也可以;同样,使用post的场景…

22 、系统安全

新的服务器到手&#xff0c;部署服务器初始化。 1、配置ip地址 网关dns解析&#xff08;static&#xff09;内网和外网。 2、安装源&#xff0c;外网&#xff08;在线即可&#xff09;&#xff0c;内网&#xff08;只能用源码包编译安装&#xff09;。 3、磁盘分区&#xff…

浅谈安科瑞ASJ10-LD1A智能漏电继电器的设计与应用-安科瑞 蒋静

一 产品简介 功能 ASJ10-LD1A安科瑞智能电力继电器 剩余电流保护可与低压断路器或低压接触器等组成组合式的剩余电流动作保护器&#xff0c;主要适用于交流50Hz&#xff0c;额定电压为400V及以下的TT或TN系统配电线路&#xff0c;防止接地故障电流引起的设备和电气火灾事故&a…

数字水印 | 盲水印嵌入:量化索引机制 QIM

目录 1 什么是量化索引调制&#xff1f;1.1 为什么使用 QIM&#xff1f;1.2 QIM 的算法思想1.3 什么是量化操作&#xff1f;1.4 论文中对 QIM 的介绍 2 盲水印论文中的实际应用2.1 均匀量化器2.2 对论文的分析 &#x1f607;说明&#xff1a;本文中的载体信息 原始信息…

VS远程调试步骤

1、背景 生产环境是没有开发环境的&#xff0c;&#xff0c;那生产环境上运行的程序&#xff0c;出了问题&#xff0c;如何远程调试它&#xff1f; 可以借助VS的远程调试。 2、步骤 1&#xff09;将E:\VS2019\install\Common7\IDE\Remote Debugger目录整体拷贝到生产环境机器…