贵阳微网站建设公司,wordpress淘宝商城,云梦网站建设,wordpress网页教程前言 测试环境#xff1a;
ffmpeg的4.3.2自行编译版本windows环境qt5.12 图片的一些重要知识#xff1a;
RGB图片
位深度#xff1a;每一个像素都会使用n个二进制位来存储颜色信息。每一个像素的颜色都是由红#xff08;Red#xff09;、绿#xff08;Green#xff0…前言 测试环境
ffmpeg的4.3.2自行编译版本windows环境qt5.12 图片的一些重要知识
RGB图片
位深度每一个像素都会使用n个二进制位来存储颜色信息。每一个像素的颜色都是由红Red、绿Green、蓝Blue3个颜色通道合成的即光的三原色。能表示2的n次方种颜色。
颜色的表示方式如十进制rgb(64, 224, 208)。十六进制#40E0D0。
一张图片的理论大小辨率是60x50位深度是24。其理论大小为(60**50)*(24/8)9000B≈8.79KB
YUV图片(原始图片数据相当于pcm)
YUV比RGB的优势1YUV比RGB的体积小一半。2YUV模式可以从黑白电视转为彩色电视过度
Y表示亮度Luminance、Luma占8bit1字节。Cb、Cr表示色度Chrominance、Chroma CbU蓝色色度分量占8bit1字节CrV红色色度分量占8bit1字节
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:CA表示一块A*2个像素的概念区域一般都是4。B表示第1行的色度采样数目。C表示第2行的色度采样数目C的值一般要么等于B要么等于0。
以下假设YUV每个分量需要1字节
4:4:4 - yuv444p 8个像素占24*8位即24字节每个像素为24/83字节4:2:2 - yuv422p 8个像素占248*4位即16字节每个像素为16/82字节4:2:0 - yuv420p 8个像素占164*8 *2位即12字节每个像素为12/81.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.yuvyuv转其他图片
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四个分量则是yuva四个分量a表示透明度
命令行yuv图片转其他格式
ffmpeg -s 564x513 -pix_fmt yuv420p -i out.yuv 1.jpg命令行查看摄像头的相关信息
ffmpeg -h demuxerdshow ---查看dshow支持的参数-video_size分辨率-pixel_format像素格式-framerate帧率每秒采集多少帧画面-list_devicestrue表示列出dshow支持的所有设备-list_optionstrue表示列出特定设备支持的所有参数ffmpeg -f dshow -list_options true -i videoIntegrated Camera ---查看摄像头支持的参数摄像头支持的像素格式和默认录制的格式可能不一样ffmpeg -f dshow -i videoIntegrated Camera out.yuv ---使用摄像头录制视频录制时的输出信息如下即录制的视频信息为分辨率1280x720像素格式yuvj422p帧率30fps
Input #0, dshow, from videoIntegrated 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 videoIntegrated 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 QThreadclass RecordYuvThread : public QThread
{Q_OBJECT
public:explicit RecordYuvThread(QObject *parent nullptr);~RecordYuvThread();signals:// QThread interface
protected:virtual void run() override;
};#endif // RECORDYUVTHREAD_HRecordYuvThread.cpp
#include recordyuvthread.h#include QDebug
#include QFileextern 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 videoIntegrated 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);// windows614400// mac615680// 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_bIsRecordYuvtrue;} else { // 点击了“结束录制”// 结束线程m_pRecordYuvThread-requestInterruption();m_pRecordYuvThread nullptr;// 设置按钮文字ui-pushButton_record_yuv-setText(开始录制);m_bIsRecordYuvfalse;}
}注意.h文件中提前声明了以下全局变量 RecordYuvThread *m_pRecordYuvThreadnullptr;bool m_bIsRecordYuvfalse;注意本文为个人记录新手照搬可能会出现各种问题请谨慎使用 码字不易如果这篇博客对你有帮助麻烦点赞收藏非常感谢有不对的地方