音视频开发—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_FMTType: Video Capture[0]: 'MJPG' (Motion-JPEG, compressed)Size: Discrete 1920x1080Interval: Discrete 0.033s (30.000 fps)Size: Discrete 640x480Interval: 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 1280x720Interval: Discrete 0.017s (60.000 fps)Interval: Discrete 0.033s (30.500 fps)Size: Discrete 1024x768Interval: Discrete 0.033s (30.000 fps)Size: Discrete 800x600Interval: Discrete 0.017s (60.000 fps)Size: Discrete 1280x1024Interval: Discrete 0.033s (30.000 fps)Size: Discrete 320x240Interval: Discrete 0.008s (120.101 fps)[1]: 'YUYV' (YUYV 4:2:2)Size: Discrete 1920x1080Interval: Discrete 0.167s (6.000 fps)Size: Discrete 640x480Interval: Discrete 0.033s (30.000 fps)Size: Discrete 1280x720Interval: Discrete 0.111s (9.000 fps)Size: Discrete 1024x768Interval: Discrete 0.167s (6.000 fps)Size: Discrete 800x600Interval: Discrete 0.050s (20.000 fps)Size: Discrete 1280x1024Interval: Discrete 0.167s (6.000 fps)Size: Discrete 320x240Interval: 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 registeredint 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 提供了一个统一的接口,用于处理各种输入数据流(文件、网络流、设备捕获)。这种设计简化了处理过程,不需要为不同的数据源提供不同的读取机制。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

刷题笔记1:如何科学的限制数字溢出问题

LCR 192. 把字符串转换成整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 我们以力扣的此题目为例&#xff0c;简述在诸如大数运算等问题中如何限制数字溢出问题。 先来直接看看自己的处理方式&#xff1a; class Solution { public:int myAtoi(string str) {int pcur0;…

【文末附gpt升级秘笈】iOS 18首个正式版与AI Siri的缺席:技术迭代与用户期待之间的博弈

iOS 18首个正式版与AI Siri的缺席&#xff1a;技术迭代与用户期待之间的博弈 摘要 随着人工智能技术的飞速发展&#xff0c;智能语音助手已成为移动设备的重要功能之一。作为移动操作系统的领导者&#xff0c;苹果的iOS系统一直以其稳定性和创新性著称。然而&#xff0c;在iO…

ssm整合(spring+springmvc+mybatis)做一个小项目(SpringMVC学习笔记六)

一、mybatis层 1、搭建数据库&#xff1a; //创建数据库 CREATE DATABASE ssmbuild; //选择数据库 USE ssmbuild//检查如果数据库中有books这个表的话就给他删除 DROP TABLE IF EXISTS books//创建表books CREATE TABLE books( bookID INT(10) NOT NULL AUTO_INCREMENT COMME…

二叉树链式结构的实现

1.创建二叉树 (1)创建结构体 typedef int BTDataType;typedef struct BinaryTreeNode {BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right; }BTNode;(2)根据前序遍历构建树 //通过前序遍历的数组"123##45##6##"构建二叉树 BTNode* Bi…

vue组合式和选项式

Vue中的组合式(Composition API)和选项式(Options API)是两种不同的编写组件逻辑的方法。 组合式API&#xff08;Composition API&#xff09;: 使用函数来定义组件逻辑&#xff0c;可以更灵活地重用和组合逻辑。使用setup函数作为组件的入口点&#xff0c;在这里可以访问pro…

docker以挂载目录启动容器报错问题的解决

拉取镜像&#xff1a; docker pull elasticsearch:7.4.2 docker pull kibana:7.4.2 创建实例&#xff1a; mkdir -p /mydata/elasticsearch/configmkdir -p /mydata/elasticsearch/dataecho "http.host: 0.0.0.0" >> /mydata/elasticsearch/config/elasti…

vs2019 c++20 规范 STL库中关于时间的模板 ratio<T,U> , duration<T,U> , time_point<T,U>等

(探讨一)在学习线程的时候&#xff0c;一些函数会让线程等待或睡眠一段时间。函数形参是时间单位&#xff0c;那么在 c 中是如何记录和表示时间的呢&#xff1f;以下给出模板简图&#xff1a; &#xff08;2 探讨二&#xff09;接着给出对模板类 duration_values 的成员函数的测…

【Leetcode 705 】设计哈希集合——数组嵌套链表(限制哈希Key)

题目 不使用任何内建的哈希表库设计一个哈希集合&#xff08;HashSet&#xff09;。 实现 MyHashSet 类&#xff1a; void add(key) 向哈希集合中插入值 key 。bool contains(key) 返回哈希集合中是否存在这个值 key 。void remove(key) 将给定值 key 从哈希集合中删除。如果…

免费企业域名备案手把手教程

走的阿里云的备案服务&#xff0c;全程免费 前提 主办者&#xff1a;你的企业主办者负责人&#xff1a;当前登录的阿里云账户的人&#xff0c;不是企业法人的话&#xff0c;得准备委托书&#xff0c;会有地方提供模板&#xff0c;打印一下&#xff0c;签字扫描上传就行域名的…

imweb前端教程:深入探索前端技术的奥秘

imweb前端教程&#xff1a;深入探索前端技术的奥秘 在数字化浪潮的推动下&#xff0c;前端技术日益成为互联网行业的核心驱动力。imweb前端教程旨在为广大前端开发者提供一份全面而深入的学习指南&#xff0c;帮助大家更好地掌握前端技术的精髓。本文将从四个方面、五个方面、…

【强化学习】DPO(Direct Preference Optimization)算法学习笔记

【强化学习】DPO&#xff08;Direct Preference Optimization&#xff09;算法学习笔记 RLHF与DPO的关系KL散度Bradley-Terry模型DPO算法流程参考文献 RLHF与DPO的关系 DPO&#xff08;Direct Preference Optimization&#xff09;和RLHF&#xff08;Reinforcement Learning f…

C++知识点

1. 构造函数&#xff1a;当没有写任何构造函数(含拷贝构造)&#xff0c;系统会生成默认的无参构造&#xff0c;并且访问属性是共有。 默认拷贝构造&#xff1a;当没有写任何的拷贝构造&#xff0c;系统会生成默认的拷贝构造->是一个浅拷贝 写了拷贝构造函数&#xff0c;这…

Kaggle线上零售 CRM分析(RFM+BG-NBD+生存分析+PySpark)

数据集地址&#xff1a;数据集地址 我的NoteBook地址&#xff1a;NoteBook地址 这个此在线零售数据集包含2009年12月1日至2011年12月9日期间的在线零售的所有交易。该公司主要销售独特的各种场合礼品。这家公司的许多客户都是批发商。本文将通过pyspark对数据进行导入与预处理&…

思迈特受邀参加工信部等权威机构行业盛会,探讨AI领域前沿技术

近日&#xff0c;思迈特软件作为国产BI领域知名厂商&#xff0c;多次受邀出席行业盛会&#xff0c;与众多业内专家学者、行业精英及知名企业代表等汇聚一堂共襄盛会&#xff0c;探讨行业前沿热点研究及最新趋势&#xff0c;分享企业数字化建设创新成果与成功实践&#xff0c;共…

Spring高手之路19——Spring AOP注解指南

文章目录 1. 背景2. 基于AspectJ注解来实现AOP3. XML实现和注解实现AOP的代码对比4. AOP通知讲解5. AOP时序图 1. 背景 在现代软件开发中&#xff0c;面向切面编程&#xff08;AOP&#xff09;是一种强大的编程范式&#xff0c;允许开发者跨越应用程序的多个部分定义横切关注点…

深度解析:重庆耶非凡科技有限公司的人力rpo项目

在当今竞争激烈的商业环境中&#xff0c;人力资源项目的成功与否往往决定了一个企业的长远发展。重庆耶非凡科技有限公司作为行业内的佼佼者&#xff0c;其人力资源项目备受瞩目。本文将深入探讨该公司的人力资源项目&#xff0c;特别是其独特的选品师项目和人力RPO服务。 首先…

【做一道算一道】无重叠区间

无重叠区间 给定一个区间的集合 intervals &#xff0c;其中 intervals[i] [starti, endi] 。返回 需要移除区间的最小数量&#xff0c;使剩余区间互不重叠 。 示例 1: 输入: intervals [[1,2],[2,3],[3,4],[1,3]] 输出: 1 解释: 移除 [1,3] 后&#xff0c;剩下的区间没有…

2024年06月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2024年06月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

安装、测试和训练OpenPCDet:一篇详尽的指南

简介 OpenPCDet是一个用于3D目标检测的开源工具箱&#xff0c;它提供了多种数据集的加载器&#xff0c;支持多种模型&#xff0c;并且易于扩展。在本博客中&#xff0c;我将引导你完成OpenPCDet的安装过程&#xff0c;并展示如何测试和训练预训练模型。 安装OpenPCDet 环境要…

数字光强测量仪OPT3001

外观 参考价格 原理图 频谱 特性 说明 OPT3001 传感器用于测量可见光的密度。传感器的光 谱响应与人眼的视觉响应紧密匹配&#xff0c;其中具有很高的红 外线阻隔。 OPT3001 是一款可如人眼般测量光强的单芯片照度 计。OPT3001 器件兼具精密的频谱响应和较强的 IR 阻隔功能&a…