十一、h.264編碼

前言


測試環境:

  • ffmpeg的4.3.2自行編譯版本
  • windows環境
  • qt5.12

使用H.264編碼對YUV視頻進行壓縮

ffmpeg -s 640x480 -pix_fmt yuv420p -i in.yuv -c:v libx264 out.h264
-c:v libx264是指定使用libx264作為編碼器

完整代碼:

H264EncodeThread.h

#ifndef H264ENCODETHREAD_H
#define H264ENCODETHREAD_H#include <QObject>
#include <QThread>extern "C" {
#include <libavutil/avutil.h>
}typedef struct {const char *filename;int width;int height;AVPixelFormat pixFmt;int fps;
} VideoEncodeSpec;class H264EncodeThread : public QThread
{Q_OBJECT
public:explicit H264EncodeThread(QObject *parent = nullptr);~H264EncodeThread();static void h264Encode(VideoEncodeSpec &in,const char *outFilename);signals:// QThread interface
protected:virtual void run() override;
};#endif // H264ENCODETHREAD_H

H264EncodeThread.cpp

#include "h264encodethread.h"extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}#include <QDebug>
#include <QFile>#define ERROR_BUF(ret) \char errbuf[1024]; \av_strerror(ret, errbuf, sizeof (errbuf));H264EncodeThread::H264EncodeThread(QObject *parent) : QThread(parent)
{// 當監聽到線程結束時(finished),就調用deleteLater回收內存connect(this,&H264EncodeThread::finished,this,[=](){this->deleteLater();qDebug()<<"RecordPcmThread線程結束,線程指針被dlete";});
}H264EncodeThread::~H264EncodeThread()
{// 斷開所有的連接disconnect();//強制關閉窗口時,線程也能安全關閉requestInterruption();wait();qDebug()<<"RecordPcmThread析構函數";
}// 檢查像素格式
static int check_pix_fmt(const AVCodec *codec,enum AVPixelFormat pixFmt) {const enum AVPixelFormat *p = codec->pix_fmts;while (*p != AV_PIX_FMT_NONE) {if (*p == pixFmt) return 1;qDebug()<<*p;p++;}return 0;
}// 返回負數:中途出現了錯誤
// 返回0:編碼操作正常完成
static int encode(AVCodecContext *ctx,AVFrame *frame,AVPacket *pkt,QFile &outFile) {// 發送數據到編碼器int ret = avcodec_send_frame(ctx, frame);if (ret < 0) {ERROR_BUF(ret);qDebug() << "avcodec_send_frame error" << errbuf;return ret;}// 不斷從編碼器中取出編碼后的數據while (true) {ret = avcodec_receive_packet(ctx, pkt);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {// 繼續讀取數據到frame,然后送到編碼器return 0;} else if (ret < 0) { // 其他錯誤return ret;}// 成功從編碼器拿到編碼后的數據// 將編碼后的數據寫入文件outFile.write((char *) pkt->data, pkt->size);// 釋放pkt內部的資源av_packet_unref(pkt);}
}void H264EncodeThread::h264Encode(VideoEncodeSpec &in, const char *outFilename)
{// 文件QFile inFile(in.filename);QFile outFile(outFilename);// 一幀圖片的大小int imgSize = av_image_get_buffer_size(in.pixFmt, in.width, in.height, 1);// 返回結果int ret = 0;// 編碼器AVCodec *codec = nullptr;// 編碼上下文AVCodecContext *ctx = nullptr;// 存放編碼前的數據(yuv)AVFrame *frame = nullptr;// 存放編碼后的數據(h264)AVPacket *pkt = nullptr;//    uint8_t *buf = nullptr;// 獲取編碼器//codec = avcodec_find_encoder_by_name("libx264");codec = avcodec_find_encoder(AV_CODEC_ID_H264);if (!codec) {qDebug() << "encoder not found";return;}// 檢查輸入數據的采樣格式if (!check_pix_fmt(codec, in.pixFmt)) {qDebug() << "unsupported pixel format"<< av_get_pix_fmt_name(in.pixFmt);return;}// 創建編碼上下文ctx = avcodec_alloc_context3(codec);if (!ctx) {qDebug() << "avcodec_alloc_context3 error";return;}// 設置yuv參數ctx->width = in.width;ctx->height = in.height;ctx->pix_fmt = in.pixFmt;//手動設置gop的數量//ctx->gop_size=5;// 設置幀率(1秒鐘顯示的幀數是in.fps)ctx->time_base = {1, in.fps};// 打開編碼器ret = avcodec_open2(ctx, codec, nullptr);if (ret < 0) {ERROR_BUF(ret);qDebug() << "avcodec_open2 error" << errbuf;goto end;}// 創建AVFrameframe = av_frame_alloc();if (!frame) {qDebug() << "av_frame_alloc error";goto end;}frame->width = ctx->width;frame->height = ctx->height;frame->format = ctx->pix_fmt;frame->pts = 0;// 利用width、height、format創建緩沖區ret = av_image_alloc(frame->data, frame->linesize,in.width, in.height, in.pixFmt, 1);if (ret < 0) {ERROR_BUF(ret);qDebug() << "av_frame_get_buffer error" << errbuf;goto end;}// 創建輸入緩沖區(方法2)
//    buf = (uint8_t *) av_malloc(imgSize);
//    ret = av_image_fill_arrays(frame->data, frame->linesize,
//                               buf,
//                               in.pixFmt, in.width, in.height, 1);
//    if (ret < 0) {
//        ERROR_BUF(ret);
//        qDebug() << "av_image_fill_arrays error" << errbuf;
//        goto end;
//    }
//    qDebug() << buf << frame->data[0];// 創建輸入緩沖區(方法3)
//    ret = av_frame_get_buffer(frame, 0);
//    if (ret < 0) {
//        ERROR_BUF(ret);
//        qDebug() << "av_frame_get_buffer error" << errbuf;
//        goto end;
//    }// 創建AVPacketpkt = av_packet_alloc();if (!pkt) {qDebug() << "av_packet_alloc error";goto end;}// 打開文件if (!inFile.open(QFile::ReadOnly)) {qDebug() << "file open error" << in.filename;goto end;}if (!outFile.open(QFile::WriteOnly)) {qDebug() << "file open error" << outFilename;goto end;}// 讀取數據到frame中while ((ret = inFile.read((char *) frame->data[0],imgSize)) > 0) {// 進行編碼if (encode(ctx, frame, pkt, outFile) < 0) {goto end;}// 設置幀的序號frame->pts++;}// 刷新緩沖區encode(ctx, nullptr, pkt, outFile);end:// 關閉文件inFile.close();outFile.close();//    av_freep(&buf);// 釋放資源if (frame) {av_freep(&frame->data[0]);
//        av_free(frame->data[0]);
//        frame->data[0] = nullptr;av_frame_free(&frame);}av_packet_free(&pkt);avcodec_free_context(&ctx);qDebug() << "線程正常結束";
}void H264EncodeThread::run()
{VideoEncodeSpec in;in.filename = "E:/media/out-yuv420p.yuv";in.width = 640;in.height = 480;in.fps = 30;in.pixFmt = AV_PIX_FMT_YUV420P;h264Encode(in, "E:/media/out-yuv420p.h264");
}

線程調用:

void MainWindow::on_pushButton_h264_encode_clicked()
{m_pH264EncodeThread=new H264EncodeThread(this);m_pH264EncodeThread->start();
}

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

	H264EncodeThread *m_pH264EncodeThread=nullptr;

注意:本文為個人記錄,新手照搬可能會出現各種問題,請謹慎使用


碼字不易,如果這篇博客對你有幫助,麻煩點贊收藏,非常感謝!有不對的地方

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/161407.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/161407.shtml
英文地址,請注明出處:http://en.pswp.cn/news/161407.shtml

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

相關文章

用HALCON標定助手對相機進行標定

任務要求&#xff1a; 已知相機鏡頭焦距f為8mm&#xff0c;相機單個CCD像素在水平和豎直兩個方向上的尺寸均為3.75微米&#xff0c;相機為普通透光鏡頭和面陣相機&#xff0c;對相機進行標定&#xff0c;測量相機的內外參數。 操作步驟&#xff1a; 1. 在HALCON中運行gen_ca…

C#使用whisper.net實現語音識別(語音轉文本)

目錄 介紹 效果 輸出信息 項目 代碼 下載 介紹 github地址&#xff1a;https://github.com/sandrohanea/whisper.net Whisper.net. Speech to text made simple using Whisper Models 模型下載地址&#xff1a;https://huggingface.co/sandrohanea/whisper.net/tree…

Nginx高級

Nginx高級 第一部分&#xff1a;擴容 通過擴容提升整體吞吐量 1.單機垂直擴容&#xff1a;硬件資源增加 云服務資源增加 整機&#xff1a;IBM、浪潮、DELL、HP等 CPU/主板&#xff1a;更新到主流 網卡&#xff1a;10G/40G網卡 磁盤&#xff1a;SAS(SCSI) HDD&#xff08;機械…

如何使用ArcGIS Pro進行坐標轉換

不同來源的數據坐標系可能是不同的&#xff0c;為了統一使用這些數據就需要進行坐標轉換&#xff0c;ArcGIS Pro作為專業的GIS軟件&#xff0c;坐標轉換功能肯定也是包含的&#xff0c;這里為大家介紹一下ArcGIS Pro如何進行坐標轉換&#xff0c;希望能對你有所幫助。 數據來源…

【Exception】npm ERR! code UNABLE_TO_GET_ISSUER_CERT_LOCALLY

Talk is cheap, show me the code. 環境 | Environment kversionOSwindows 11nodev18.14.2npm9.5.0 報錯日志 | Error log >npm create vitelatest Need to install the following packages:create-vite5.0.0 Ok to proceed? (y) y npm ERR! code UNABLE_TO_GET_ISSUER_…

2023亞太杯數學建模B題思路+模型+代碼+論文

2023亞太地區數學建模A題思路&#xff1a;開賽后第一時間更新&#xff0c;獲取見文末 名片 2023亞太地區數學建模B題思路&#xff1a;開賽后第一時間更新&#xff0c;獲取見文末 名片 2023亞太地區數學建模C題思路&#xff1a;開賽后第一時間更新&#xff0c;獲取見文末 名片…

idea修改行號顏色

前言 i當idea用了深色主題后&#xff0c;發現行號根本看不清&#xff0c;或者很模糊 例如下面這樣 修改行號顏色 在IntelliJ IDEA中&#xff0c;你可以根據自己的喜好和需求定制行號的顏色。下面是修改行號顏色的步驟&#xff1a; 打開 IntelliJ IDEA。 轉到 “File”&…

ChatGPT規模化服務的經驗與教訓

2022年11月30日&#xff0c;OpenAI發布ChatGPT&#xff0c;以很多人未曾預料的速度迅速走紅。與此同時&#xff0c;由于短時間內用戶量的暴漲&#xff0c;導致服務器過載&#xff0c;迫使OpenAI停止新用戶的注冊。 ChatGPT發布這一年&#xff0c;同樣的情景發生了好幾次。在最近…

opencv-圖像金字塔

圖像金字塔是一種圖像處理技術&#xff0c;它通過不斷降低圖像的分辨率&#xff0c;形成一系列圖像。金字塔分為兩種類型&#xff1a;高斯金字塔和拉普拉斯金字塔。 高斯金字塔&#xff08;Gaussian Pyramid&#xff09;&#xff1a; 高斯金字塔是通過使用高斯濾波和降采樣&a…

專業遠程控制如何塑造安全體系?向日葵“全流程安全閉環”解析

安全是遠程控制的重中之重&#xff0c;作為國民級遠程控制品牌&#xff0c;向日葵遠程控制就極為注重安全遠控服務的塑造。近期向日葵發布了以安全和核心的新版“向日葵15”以及同步發布《貝銳向日葵遠控安全標準白皮書》&#xff08;下簡稱《白皮書》&#xff09;&#xff0c;…

使用微信小程序openMapApp接口,報錯問題解決openMapApp:fail invaild coord

使用微信小程序的 openMapApp 接口時遇到了坐標無效的錯誤 (openMapApp:fail invalid coord)。這個錯誤通常是由于提供的地理坐標不符合預期的格式或范圍而引起的&#xff1a; 坐標格式&#xff1a; 確保提供的坐標符合正確的格式。常見的格式是 "緯度,經度"&#xf…

【11月比賽合集】5場可報名的「創新應用」、「數據分析」和「程序設計」大獎賽,任君挑選!

CompHub[1] 實時聚合多平臺的數據類(Kaggle、天池…)和OJ類(Leetcode、牛客…&#xff09;比賽。本賬號會推送最新的比賽消息&#xff0c;歡迎關注&#xff01; 以下信息僅供參考&#xff0c;以比賽官網為準 目錄 創新應用賽&#xff08;1場比賽&#xff09;數據分析賽&#…

逸學java【初級菜鳥篇】9.3 Stream流

hi&#xff0c;我是逸塵&#xff0c;一起學java吧 得益于Lambda所帶來的函數式編程&#xff0c;引入了一個全新的Stream流概念&#xff08;就是都基本使用lambda的形式&#xff09;。 流處理 我們首先理解什么是流處理&#xff0c;它類似于sql語句&#xff0c;可以執行非常復…

【開源】基于Vue和SpringBoot的智能教學資源庫系統

項目編號&#xff1a; S 050 &#xff0c;文末獲取源碼。 \color{red}{項目編號&#xff1a;S050&#xff0c;文末獲取源碼。} 項目編號&#xff1a;S050&#xff0c;文末獲取源碼。 目錄 一、摘要1.1 項目介紹1.2 項目錄屏 二、功能模塊2.1 數據中心模塊2.2 課程檔案模塊2.3 課…

原理Redis-SkipList

SkipList ZipList和QuickList的共同特點是節省內存。在遍歷元素時&#xff0c;只能從頭到尾或從尾到頭&#xff0c;所以在查找頭尾元素性能還是不錯的&#xff0c;但是中間元素查詢的性能就會差。 **SkipList&#xff08;跳表&#xff09;**首先是鏈表&#xff0c;但與傳統鏈表…

【算法】鏈表-20231123

這里寫目錄標題 一、19. 刪除鏈表的倒數第 N 個結點二、21. 合并兩個有序鏈表三、24. 兩兩交換鏈表中的節點 一、19. 刪除鏈表的倒數第 N 個結點 提示 中等 給你一個鏈表&#xff0c;刪除鏈表的倒數第 n 個結點&#xff0c;并且返回鏈表的頭結點。 輸入&#xff1a;head [1,…

第十二章 : Spring Boot 日志框架詳解

第十二章 : Spring Boot 日志框架詳解 前言 本章知識重點:介紹了日志誕生背景,4種日志框架:Logback、Log4j、Log4j2和Slf4j的優劣勢分析,以及重點介紹了log4j2的應用示例以及配置,以及日志框架應用中遇到常見的問題以及如何處理。 背景 Java日志框架的發展歷程可以追…

在PyCharm中正確設置Python項目

大家好&#xff0c;在Mac和Linux都支持Python&#xff0c;但許多開發者發現正確設置Python項目很困難。本文匯總了多平臺中運行Python的方法&#xff0c;提高編程的效率&#xff0c;如下所示&#xff1a; 使用命令行運行Python。 在PyCharm&#xff08;免費社區版&#xff09;…

【技巧】PDF文件如何編輯?

日常辦公中我們經常會用到PDF文件&#xff0c;PDF具備很好的兼容性、穩定性及安全性&#xff0c;但卻不容易編輯&#xff0c;那PDF要如何編輯呢&#xff1f; 如果打開PDF文件就只是只讀的性質&#xff0c;說明文件是在線打開&#xff0c;或者通過PDF閱讀器打開的&#xff0c;這…

Navmesh 尋路

用cocos2dx引擎簡單實現了一下navmesh的多邊形劃分&#xff0c;然后基于劃分多邊形的a*尋路。以及路徑拐點優化算法 用cocos主要是方便使用一些渲染接口和定時器。重點是實現的原理。 首先畫了一個帶有孔洞的多邊形 //多邊形的頂點數據Vec2(100, 100),Vec2(300, 200),Vec2(50…