八、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.pswp.cn/news/161684.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/161684.shtml
英文地址,請注明出處:http://en.pswp.cn/news/161684.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【python】python旅游網數據抓取分析(源碼+論文)【獨一無二】

&#x1f449;博__主&#x1f448;&#xff1a;米碼收割機 &#x1f449;技__能&#x1f448;&#xff1a;C/Python語言 &#x1f449;公眾號&#x1f448;&#xff1a;測試開發自動化【獲取源碼商業合作】 &#x1f449;榮__譽&#x1f448;&#xff1a;阿里云博客專家博主、5…

C語言——結構體的應用

歸納編程學習的感悟&#xff0c; 記錄奮斗路上的點滴&#xff0c; 希望能幫到一樣刻苦的你&#xff01; 如有不足歡迎指正&#xff01; 共同學習交流&#xff01; &#x1f30e;歡迎各位→點贊 &#x1f44d; 收藏? 留言?&#x1f4dd; 路還在繼續&#xff0c;夢還在期…

webGL技術開發的軟件類型

WebGL 是一種在瀏覽器中渲染 2D 和 3D 圖形的 JavaScript API。通過 WebGL&#xff0c;你可以創建各種類型的軟件項目&#xff0c;特別是那些需要強大圖形渲染能力的項目。以下是一些你可以使用 WebGL 實現的軟件項目類型&#xff0c;希望對大家有所幫助。北京木奇移動技術有限…

老生常談之 JavaScript 中 0.1 + 0.2 != 0.3 的原因

先來一個模棱兩可的說法&#xff1a;因為精度丟失、存儲溢出的問題 先復習一下二進制的轉換方法&#xff1a; 整數&#xff1a;除以基數&#xff0c;取余&#xff0c;自底向上小數&#xff1a;乘以基數&#xff0c;取整&#xff0c;自頂向下 接著&#xff0c;復習一下雙精度…

Linux使用操作

各類小技巧 ctrlc強制停止 ctrld退出賬戶的登錄 或者退出某些特定程序的專屬頁面 history 查看歷史命令 !命令前綴&#xff0c;自動執行上一次匹配前綴的命令 ctrlr 輸入內容去匹配歷史命令 光標移動快捷鍵 ctrla&#xff0c;跳到命令開頭 ctrle&#xff0c;跳到命令結尾…

【C語言_題庫】輸入4個整數,要求按照從小到大的順序輸出

題目 輸入4個整數 要求按照從小到大的順序輸出 書上的學習輔導答案 // 主要部分 int main(){int t,a,b,c,d;printf("請輸入四個數:");scanf("%d,%d,%d,%d"

SkyWalking全景解析:從原理到實現的分布式追蹤之旅

&#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交給時間 &#x1f3e0; &#xff1a;小破站 SkyWalking全景解析&#xff1a;從原理到實現的分布式追蹤之旅 前言第一&#xff1a;SkyWalking簡介第二&#xff1a;實現原理概覽第三&#xff1a;主鍵與架構第四&#xff1…

【計算機基礎】通過插件plantuml,實現在VScode里面繪制狀態機

&#x1f4e2;&#xff1a;如果你也對機器人、人工智能感興趣&#xff0c;看來我們志同道合? &#x1f4e2;&#xff1a;不妨瀏覽一下我的博客主頁【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸對你有幫助&#xff0c;可點贊 &#x1f44d;…

數學與她的

文章目錄 定義域函數的定義域&#xff1a;一般地復合函數求解極值&#xff0c;單調性綜合考題&#xff1a; 定義域 函數的定義域&#xff1a; 求定義域的原則性問題&#xff08;通用&#xff09;分母不為0 偶次根式的被開方式為非負&#xff08; ≥ 0 &#xff09; 偶次根式的…

redis運維(十五) 集合

一 集合 ① 概念 集合的元素在redis里面的世界是member集合&#xff1a; setset集合當中不允許重復的元素&#xff0c;而且set集合當中元素是沒有順序的,不存在元素下標 ② sadd、smembers、srem ③ sismember、srandmember、spop、scard spop 命令用于移除集合中的指定 …

sql語法大全

1&#xff0c;創建數據庫 create database 數據庫名字; 2,查看所有的數據庫名稱 show databases; MySQL服務器已有4個數據庫&#xff0c;這些數據庫都是MySQL安裝時自動創建的。 information_schema 和 performance_schema 數據庫分別是 MySQL 服務器的數據字典&#xff08;…

CSS 漸變

linear-gradient() 線性漸變 /* 漸變軸為 45 度&#xff0c;從藍色漸變到紅色 */ linear-gradient(45deg, blue, red);/* 從右下到左上、從藍色漸變到紅色 */ linear-gradient(to left top, blue, red); /* to [left/right] [top/bottom] *//* 色標&#xff1a;從下到上&#…

算法——滑動窗口(Sliding Window)

一、背景知識 滑動窗口算法&#xff08;Sliding Window&#xff09;&#xff1a; 在給定數組 / 字符串上維護一個固定長度或不定長度的窗口。可以對窗口進行滑動操作、縮放操作&#xff0c;以及維護最優解操作。題型一&#xff1a;固定長度題型二&#xff1a;不固定長度 二、例…

TypeScript 學習筆記 第二部分 webpack 創建typescript項目

【視頻鏈接】尚硅谷TypeScript教程&#xff08;李立超老師TS新課&#xff09; 創建webpack 項目 IDE&#xff1a;webstorm 新建一個空的項目運行npm init初始化項目目錄結構 1. 安裝 webpack&#xff1a;構建工具webpack-cli&#xff1a; webpack的命令行工具typescript&am…

PCIE鏈路訓練-狀態機描述1

狀態機描述 Config.linkwidth.start&#xff1a; 1. &#xff08;1&#xff09;Linkup 0 狀態機沒有執行鏈路寬度的升級&#xff08;upconfiguration of the Link width&#xff09;&#xff1a;那么tx會在所有active的dsp上發送TS1&#xff0c;其中link num為具體內容&a…

git stash 用法總結

目錄 1&#xff0c;介紹場景1&#xff1a;場景2&#xff1a; 2&#xff0c;常用命令2.1&#xff0c;基礎2.2&#xff0c;進階1&#xff0c;存儲時指定備注2&#xff0c;通過索引來操作指定的存儲3&#xff0c;修改存儲規則 2.3&#xff0c;查看 stash 修改的具體內容 1&#xf…

Element UI之Dialog 對話框

Dialog 對話框 用于彈出窗口 按需引入方式 如果是完整引入可跳過此步驟 import Vue from vue import { Dialog } from element-ui import element-ui/lib/theme-chalk/base.css import element-ui/lib/theme-chalk/dialog.cssVue.use(Dialog)基礎使用 <template><…

摩爾定律,梅特卡夫定律,吉爾德定律

信息系統的三大定律(摩爾定律&#xff0c;梅特卡夫定律&#xff0c;吉爾德定律)有一個清晰的視角&#xff1a; 信息系統不是左邊的生產消費系統&#xff0c;而是右邊的交易系統&#xff0c;交易系統與生產消費典型的區別在于信息交易過程會產生新的信息&#xff0c;就像錢一樣…

c語言——俄羅斯方塊

一、游戲效果 俄羅斯方塊 二. 游戲背景 俄羅斯方塊是久負盛名的游戲&#xff0c;它也和貪吃蛇&#xff0c;掃雷等游戲位列經典游戲的?列。 《俄羅斯方塊》&#xff08;Tetris&#xff0c;俄文&#xff1a;Тетрис&#xff09;是一款由俄羅斯人阿列克謝帕基特諾夫于1984…

java http

超文本傳輸協議 超文本/html 工作方式 get / url 請求獲取相應報文 http://xxxxxxxxxxxx.com/user?xxx xxx 協議類型 - 服務器地址 -路徑 path 請求格式: head / body path路徑進行處理資源 等同于報文請求: GET: /users HTTP/1.1 Host:api.github.com 響應報文 請求方式…