八、ffmpeg录制视频为yuv文件

前言


测试环境:

  • ffmpeg的4.3.2自行编译版本
  • windows环境
  • qt5.12

图片的一些重要知识:

RGB图片

  • 位深度:每一个像素都会使用n个二进制位来存储颜色信息。每一个像素的颜色都是由红(Red)、绿(Green)、蓝(Blue)3个颜色通道合成的,即光的三原色。能表示2的n次方种颜色。

颜色的表示方式:如十进制:rgb(64, 224, 208)。十六进制:#40E0D0。

一张图片的理论大小:辨率是60x50,位深度是24。其理论大小为(60**50)*(24/8)=9000B≈8.79KB

YUV图片(原始图片数据,相当于pcm)

YUV比RGB的优势:(1)YUV比RGB的体积小一半。(2)YUV模式可以从黑白电视转为彩色电视过度

  • Y:表示亮度(Luminance、Luma),占8bit(1字节)。
  • Cb、Cr:表示色度(Chrominance、Chroma)
    • Cb(U):蓝色色度分量,占8bit(1字节)
    • Cr(V):红色色度分量,占8bit(1字节)

Y分量对清晰度影响巨大,所以可以减少UV分量以达到压缩的目的。(眼对亮度的敏感程度要高于对色度的敏感程度,人眼对于亮度的分辨要比对颜色的分辨精细一些)。即色度二次采样:如果在色度分量上进行(相对亮度分量)较低分辨率的采样,也就是存储较多的亮度细节、较少的色度细节,这样就可以在不明显降低画面质量的同时减小图像的体积。

注:YUV和RGB是可以进行转换的,如:

公式一:

Y = 0.257R + 0.504G + 0.098B + 16
U = -0.148R - 0.291G + 0.439B + 128
V = 0.439R - 0.368G - 0.071B + 128R = 1.164(Y - 16) + 2.018(U - 128)
G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
B = 1.164(Y - 16) + 1.596(V - 128)RGB的取值范围是[0,255]
Y的取值范围是[16,235]
UV的取值范围是[16,239]    

公式二:

Y = 0.299R + 0.587G + 0.114B
U = 0.564(B - Y) = -0.169R - 0.331G + 0.500B
V = 0.713(R - Y) = 0.500R - 0.419G - 0.081BR = Y + 1.403V
G = Y - 0.344U - 0.714V
B = Y + 1.770URGB的取值范围是[0, 1]
Y的取值范围是[0, 1]
UV的取值范围是[-0.5, 0.5]    

公式三:

Y = 0.299R + 0.587G + 0.114B
U = -0.169R - 0.331G + 0.500B + 128
V = 0.500R - 0.419G - 0.081B + 128R = Y + 1.403(V - 128)
G = Y - 0.343(U - 128) - 0.714(V - 128)
B = Y + 1.770(U - 128)RGB的取值范围是[0, 255]
YUV的取值范围是[0, 255]

下面需要重点讲解一下色度二次采样通过何种方式达到高清晰小体积的

采样格式(像素格式)

若要进行色度二次采样,则采样格式有三种,A:B:C,A表示一块A*2个像素的概念区域,一般都是4。B表示第1行的色度采样数目。C表示第2行的色度采样数目(C的值一般要么等于B,要么等于0)。

以下假设YUV每个分量需要1字节

  • 4:4:4 -> yuv444p (8个像素,占24*8位,即24字节,每个像素为24/8=3字节)
  • 4:2:2 -> yuv422p (8个像素,占(24+8)*4位,即16字节,每个像素为16/8=2字节)
  • 4:2:0 -> yuv420p (8个像素,占(16+4*8) *2位,即12字节,每个像素为12/8=1.5字节)

如下是4*2像素的情况下,采样的方式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

色度二次采样记录每个位置的亮度信息,再记录部分位置的色度信息。结合起来就达到了,尽可能高的分辨率和尽可能大的压缩

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


采样完成之后,还要考虑YUV三个分量的存储方式(每个Y、U、V分别占一个字节,完整的YUV理论上是3字节,24位)

YUV数据的存储格式(YUV图片相当于pcm图片)

  • Planar(平面),Y、U、V分量分开单独存储,以p结尾
  • Semi-Planar(半平面),Y分量单独存储,U、V分量交错存储,以字母sp结尾
  • Packed(紧凑)又叫Interleaved (交错),Y、U、V分量交错存储

以yuv42p举例,将样式图按照字节流排列如下(下图应该代表24个像素,因为有24个Y分量)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

采样格式+存储格式=像素格式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


命令行其他格式图片转yuv图片

ffmpeg -i 1.png -s 1928x1048 -pixel_format yuv420p out.yuv

yuv转其他图片

ffmpeg -s 1928x1048 -pixel_format yuv420p -i in.yuv out.jpg

命令行播放yuv图片

ffplay -video_size 1928x1048 -pixel_format yuv420p out.yuv

查看ffmpeg支持的像素格式

ffmpeg -pix_fmts | findstr 444

image-20230104145850765

四个分量则是yuva四个分量,a表示透明度

命令行yuv图片转其他格式

ffmpeg -s 564x513 -pix_fmt yuv420p -i out.yuv 1.jpg

命令行查看摄像头的相关信息

ffmpeg -h demuxer=dshow		---查看dshow支持的参数-video_size:分辨率-pixel_format:像素格式-framerate:帧率(每秒采集多少帧画面)-list_devices:true表示列出dshow支持的所有设备-list_options:true表示列出特定设备支持的所有参数ffmpeg -f dshow -list_options true -i video="Integrated Camera"		---查看摄像头支持的参数(摄像头支持的像素格式和默认录制的格式可能不一样)ffmpeg -f dshow -i video="Integrated Camera" out.yuv    	---使用摄像头录制视频

录制时的输出信息如下,即录制的视频信息为,分辨率:1280x720,像素格式:yuvj422p,帧率:30fps

Input #0, dshow, from 'video=Integrated Camera':Stream #0:0: Video: mjpeg, yuvj422p, 1280x720, 30 fpsOutput #0, rawvideo, to 'out.yuv':Stream #0:0: Video: rawvideo, yuvj422p, 1280x720, 30 fps

自定义参数进行摄像头录制

#    
ffmpeg -f dshow -video_size 640x480 -pixel_format yuyv422 -framerate 30 -i video="Integrated Camera" out.yuv		---自定义参数录制视频    #
ffplay -video_size 1280x720 -pixel_format yuvj422p -framerate 30 out.yuv 		---播放摄像头录制的视频  -framerate:帧率

音频录制及播放的最基本要素:

  • 分辨率:如1080x720,-video_size
  • 像素格式:即采样格式,如yuvj422p,-pixel_format
  • 帧率:-framerate

注:YUV中没有声音,只有在最基本的图像信息


完整代码:

RecordYuvThread.h

#ifndef RECORDYUVTHREAD_H
#define RECORDYUVTHREAD_H#include <QObject>
#include <QThread>class RecordYuvThread : public QThread
{Q_OBJECT
public:explicit RecordYuvThread(QObject *parent = nullptr);~RecordYuvThread();signals:// QThread interface
protected:virtual void run() override;
};#endif // RECORDYUVTHREAD_H

RecordYuvThread.cpp

#include "recordyuvthread.h"#include <QDebug>
#include <QFile>extern "C" {
// 设备
#include <libavdevice/avdevice.h>
// 格式
#include <libavformat/avformat.h>
// 工具(比如错误处理)
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
}#ifdef Q_OS_WIN// 格式名称#define FMT_NAME "dshow"// 设备名称#define DEVICE_NAME "video=Integrated Camera"// YUV文件名#define FILENAME "E:/media/out-yuyv422.yuv"
#else#define FMT_NAME "avfoundation"#define DEVICE_NAME "0"#define FILEPATH "/Users/mj/Desktop/out.yuv"
#endif#define ERROR_BUF(ret) \char errbuf[1024]; \av_strerror(ret, errbuf, sizeof (errbuf));RecordYuvThread::RecordYuvThread(QObject *parent) : QThread(parent)
{// 当监听到线程结束时(finished),就调用deleteLater回收内存connect(this,&RecordYuvThread::finished,this,[=](){this->deleteLater();qDebug()<<"RecordYuvThread线程结束";});
}RecordYuvThread::~RecordYuvThread()
{// 断开所有的连接disconnect();// 内存回收之前,正常结束线程requestInterruption();// 安全退出quit();wait();qDebug() << this << "析构(内存被回收)";
}void RecordYuvThread::run()
{// 获取输入格式对象AVInputFormat *fmt = av_find_input_format(FMT_NAME);if (!fmt) {qDebug() << "av_find_input_format error" << FMT_NAME;return;}// 格式上下文(将来可以利用上下文操作设备)AVFormatContext *ctx = nullptr;// 设备参数AVDictionary *options = nullptr;av_dict_set(&options, "video_size", "640x480", 0);av_dict_set(&options, "pixel_format", "yuyv422", 0);av_dict_set(&options, "framerate", "30", 0);//    av_dict_set(&options, "video_size", "1280x720", 0);
//    av_dict_set(&options, "pixel_format", "yuyv422", 0);
//    av_dict_set(&options, "framerate", "10", 0);// 打开设备int ret = avformat_open_input(&ctx, DEVICE_NAME, fmt, &options);if (ret < 0) {ERROR_BUF(ret);qDebug() << "avformat_open_input error" << errbuf;return;}// 文件名QFile file(FILENAME);// 打开文件if (!file.open(QFile::WriteOnly)) {qDebug() << "file open error" << FILENAME;// 关闭设备avformat_close_input(&ctx);return;}// 计算一帧的大小AVCodecParameters *params = ctx->streams[0]->codecpar;AVPixelFormat pixFmt = (AVPixelFormat) params->format;int imageSize = av_image_get_buffer_size(pixFmt,params->width,params->height,1);//    qDebug() << imageSize;
//    qDebug() << pixFmt << params->width << params->height;
//    qDebug() << av_pix_fmt_desc_get(pixFmt)->name;
//    int pixSize = av_get_bits_per_pixel(av_pix_fmt_desc_get(pixFmt)) >> 3;
//    int imageSize = params->width * params->height * pixSize;// 数据包AVPacket *pkt = av_packet_alloc();while (!isInterruptionRequested()) {// 不断采集数据ret = av_read_frame(ctx, pkt);if (ret == 0) { // 读取成功// 将数据写入文件file.write((const char *) pkt->data, imageSize);// windows:614400// mac:615680// qDebug() << pkt->size;// 释放资源av_packet_unref(pkt);} else if (ret == AVERROR(EAGAIN)) { // 资源临时不可用continue;} else { // 其他错误ERROR_BUF(ret);qDebug() << "av_read_frame error" << errbuf << ret;break;}}// 释放资源av_packet_free(&pkt);// 关闭文件file.close();// 关闭设备avformat_close_input(&ctx);
}

线程调用:

void MainWindow::on_pushButton_record_yuv_clicked()
{if (!m_bIsRecordYuv) { // 点击了“开始录制”// 开启线程m_pRecordYuvThread = new RecordYuvThread(this);m_pRecordYuvThread->start();connect(m_pRecordYuvThread, &RecordYuvThread::finished,[this]() { // 线程结束m_pRecordYuvThread = nullptr;ui->pushButton_record_yuv->setText("开始录制");});// 设置按钮文字ui->pushButton_record_yuv->setText("结束录制");m_bIsRecordYuv=true;} else { // 点击了“结束录制”// 结束线程m_pRecordYuvThread->requestInterruption();m_pRecordYuvThread = nullptr;// 设置按钮文字ui->pushButton_record_yuv->setText("开始录制");m_bIsRecordYuv=false;}
}

注意:.h文件中提前声明了以下全局变量

	RecordYuvThread *m_pRecordYuvThread=nullptr;bool m_bIsRecordYuv=false;

注意:本文为个人记录,新手照搬可能会出现各种问题,请谨慎使用


码字不易,如果这篇博客对你有帮助,麻烦点赞收藏,非常感谢!有不对的地方

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

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

相关文章

Linux学习笔记-Ubuntu下使用Crontab设置定时任务

文章目录 一、概述二、基于crontab的设置2.1 基本命令说明2.2 使用-e指令编辑命令2.2.1 进入编辑模式2.2.2 指令信息格式2.2.4 开启日志1) 修改rsyslog配置文件2) 重启rsyslog3) 查看日志 2.2.3 设置后之后重启服务 三、示例3.1 每隔一分钟往文件中日期3.2 使用-l查看任务列表3…

教你如何将Web项目部署到Linux中

文章目录 前言0. 什么是部署1. 调整代码达成一致2. 数据库建表3. 构建项目并打包4. 拷贝到 Tomcat 中5. 效果总结 前言 在我们完成了一个Web项目后, 我们该怎样将项目部署到 Linux 系统中呢? 本文就来简单讲解一下. 文章已部署本人的博客系统代码展开讲解. 关注收藏, 开始学…

【Spring】SpringBoot的扩展点之ApplicationContextInitializer

简介 其实spring启动步骤中最早可以进行扩展的是实现ApplicationContextInitializer接口。来看看这个接口的注释。 package org.springframework.context;/*** Callback interface for initializing a Spring {link ConfigurableApplicationContext}* prior to being {linkpl…

ChatGPT规模化服务的经验与教训

2022年11月30日&#xff0c;OpenAI发布ChatGPT&#xff0c;以很多人未曾预料的速度迅速走红。与此同时&#xff0c;由于短时间内用户量的暴涨&#xff0c;导致服务器过载&#xff0c;迫使OpenAI停止新用户的注册。 ChatGPT发布这一年&#xff0c;同样的情景发生了好几次。在最近…

暖阳脚本_ 将Agent技术的灵活性引入RPA,清华等发布自动化智能体ProAgent

RPA暖阳脚本 近日&#xff0c;来自清华大学的研究人员联合面壁智能、中国人民大学、MIT、CMU 等机构共同发布了新一代流程自动化范式 “智能体流程自动化” Agentic Process Automation&#xff08;APA&#xff09;&#xff0c;结合大模型智能体帮助人类进行工作流构建&#x…

微信小程序会议OA-登录获取手机号流程登录-小程序导入微信小程序SDK(从微信小程序和会议OA登录获取手机号到登录小程序导入微信小程序SDK)

目录 获取用户昵称头像和昵称 wx.getUserProfile bindgetuserinfo 登录过程 登录-小程序 wx.checkSession wx.login wx.request 后台 准备数据表 反向生成工具生成 准备封装前端传过来的数据 小程序服器配置 导入微信小程序SDK application.yml WxProperties …

ABAP调用Https接口 Ssl证书导入

ABAP调用Https接口 Ssl证书导入 一、证书导入 谷歌浏览器打开对方系统URL地址&#xff0c;下载SSL Server certificate,步骤如下&#xff1a; 浏览器打开要导出certificate(证书)的网站&#xff0c;点击这个小锁的图标&#xff1a; 点击连接是安全的后面小播放按钮 点击证…

解决ElementUI时间选择器回显出现Wed..2013..中国标准时间.

使用饿了么组件 时间日期选择框回显到页面为啥是这样的&#xff1f; 为什么再时间框中选择日期&#xff0c;回显页面出现了这种英文格式呢&#xff1f;&#xff1f;&#xff1f;&#xff1f; 其实这个问题直接使用elementui的内置属性就能解决 DateTimePicker 日期时间选择…

汇编-PROTO声明过程

64位汇编 64 模式中&#xff0c;PROTO 伪指令指定程序的外部过程&#xff0c;示例如下&#xff1a; ExitProcess PROTO ;指定外部过程&#xff0c;不需要参数.code main PROCmov ebx, 0FFFFFFFFh mov ecx,0 ;结束程序call ExitProcess ;调用外部过程main ENDP END 32位…

【华为OD题库-032】数字游戏-java

题目 小明玩一个游戏。系统发1n张牌&#xff0c;每张牌上有一个整数。第一张给小明&#xff0c;后n张按照发牌顺序排成连续的一行。需要小明判断&#xff0c;后n张牌中&#xff0c;是否存在连续的若干张牌&#xff0c;其和可以整除小明手中牌上的数字. 输入描述: 输入数据有多组…

redis---非关系型数据库

关系数据库与非关系型数据库 redis非关系型数据库&#xff0c;又名缓存型数据库。数据库类型&#xff1a;关系型数据库和非关系型数据库关系型数据库是一 个机构化的数据库,行和列。 列&#xff1a;声明对象。 行&#xff1a;记录对象属性。 表与表之间的的关联。 sql语句&…

实验7设计建模工具的使用(三)

二&#xff0c;实验内容与步骤 1. 百度搜索1-2张状态图&#xff0c;请重新绘制它们&#xff0c;并回答以下问题&#xff1a; 1&#xff09;有哪些状态&#xff1b; 2&#xff09;简要描述该图所表达的含义&#xff1b; 要求&#xff1a;所绘制的图不得与本文中其它习题一样…

python django 小程序图书借阅源码

开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…

神经网络中BN层简介及位置分析

1. 简介 Batch Normalization是深度学习中常用的技巧&#xff0c;Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift (Ioffe and Szegedy, 2015) 第一次介绍了这个方法。 这个方法的命名&#xff0c;明明是Standardization, 非…

【考研数学】数学一“背诵”手册(一)| 高数部分(2)

文章目录 引言一、高数级数空间解析几何球坐标变换公式零碎公式 写在最后 引言 高数一篇文章还是写不太下&#xff0c;再分一些到这里来吧 一、高数 级数 阿贝尔定理&#xff1a;若级数 ∑ a n x n \sum a_nx^n ∑an​xn 当 x x 0 xx_0 xx0​ 时收敛&#xff0c;则适合不…

计算机毕业设计选题推荐-点餐微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

边缘计算多角色智能计量插座 x 资产显示标签:实现资产追踪与能耗管理的无缝结合

越来越多智慧园区、智慧工厂、智慧医院、智慧商业、智慧仓储物流等企业商家对精细化、多元化智能生态应用场景的提升&#xff0c;顺应国家节能减排、环保的时代潮流&#xff0c;设计一款基于融合以太网/WiFi/蓝牙智能控制的智能多角色插座应运而生&#xff0c;赋予智能插座以遥…

微博头条文章开放接口报错 auth by Null spi

接口文档地址 https://open.weibo.com/wiki/Toutiao/api 接口说明 https://api.weibo.com/proxy/article/publish.json 请求方式 POST 请求参数 参数名称类型是否必需描述titlestring是文章标题&#xff0c;限定32个中英文字符以内contentstring是正文内容&#xff0c;限制9…

竞赛 : 题目:基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

Java 编码

编码: 加密: 通过加密算法和密钥进行 也可通过码表进行加密 对称加密: 缺点:可被截获 元数据---加密算法密钥密文 ----> 解密算法密钥元数据 算法:DES(短 56位),AES(长 128位)破解时间加长 非对称加密: 元数据-加密算法加密密钥 密文 --->加密算法解密密钥元数据 …