十二、h.264解碼

前言


測試環境:

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

完整代碼:

H264DncodeThread.h

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

H264DncodeThread.cpp

#include "h264dncodethread.h"#include <QDebug>
#include <QFile>extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
}#define ERROR_BUF(ret) \char errbuf[1024]; \av_strerror(ret, errbuf, sizeof (errbuf));// 輸入緩沖區的大小
#define IN_DATA_SIZE 4096static int frameIdx = 0;static int decode(AVCodecContext *ctx,AVPacket *pkt,AVFrame *frame,QFile &outFile) {// 發送壓縮數據到解碼器int ret = avcodec_send_packet(ctx, pkt);if (ret < 0) {ERROR_BUF(ret);qDebug() << "avcodec_send_packet error" << errbuf;return ret;}while (true) {// 獲取解碼后的數據ret = avcodec_receive_frame(ctx, frame);if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {return 0;} else if (ret < 0) {ERROR_BUF(ret);qDebug() << "avcodec_receive_frame error" << errbuf;return ret;}qDebug() << "解碼出第" << ++frameIdx << "幀";// 將解碼后的數據寫入文件// 寫入Y平面outFile.write((char *) frame->data[0],frame->linesize[0] * ctx->height);// 寫入U平面outFile.write((char *) frame->data[1],frame->linesize[1] * ctx->height >> 1);// 寫入V平面outFile.write((char *) frame->data[2],frame->linesize[2] * ctx->height >> 1);//        qDebug() << frame->data[0] << frame->data[1] << frame->data[2];/** frame->data[0] 0xd08c400 0x8c400* frame->data[1] 0xd0d79c0 0xd79c0* frame->data[2] 0xd0ea780 0xea780** frame->data[1] - frame->data[0] = 308672 = y平面的大小* frame->data[2] - frame->data[1] = 77248 = u平面的大小** y平面的大小 640x480*1 = 307200* u平面的大小 640x480*0.25 = 76800* v平面的大小 640x480*0.25*///        // 將解碼后的數據寫入文件(460800)
//        int imgSize = av_image_get_buffer_size(ctx->pix_fmt, ctx->width, ctx->height, 1);
//        // outFile.write((char *) frame->data[0], frame->linesize[0]);
//        outFile.write((char *) frame->data[0], imgSize);}
}H264DncodeThread::H264DncodeThread(QObject *parent) : QThread(parent)
{// 當監聽到線程結束時(finished),就調用deleteLater回收內存connect(this,&H264DncodeThread::finished,this,[=](){this->deleteLater();qDebug()<<"H264DncodeThread線程結束,線程指針被dlete";});
}H264DncodeThread::~H264DncodeThread()
{// 斷開所有的連接disconnect();//強制關閉窗口時,線程也能安全關閉requestInterruption();wait();qDebug()<<"H264DncodeThread析構函數";
}void H264DncodeThread::h264Decode(const char *inFilename, VideoDecodeSpec &out)
{// 返回結果int ret = 0;// 用來存放讀取的輸入文件數據(h264)// 加上AV_INPUT_BUFFER_PADDING_SIZE是為了防止某些優化過的reader一次性讀取過多導致越界char inDataArray[IN_DATA_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];char *inData = inDataArray;// 每次從輸入文件中讀取的長度(h264)// 輸入緩沖區中,剩下的等待進行解碼的有效數據長度int inLen;// 是否已經讀取到了輸入文件的尾部int inEnd = 0;// 文件QFile inFile(inFilename);QFile outFile(out.filename);// 解碼器AVCodec *codec = nullptr;// 上下文AVCodecContext *ctx = nullptr;// 解析器上下文AVCodecParserContext *parserCtx = nullptr;// 存放解碼前的數據(h264)AVPacket *pkt = nullptr;// 存放解碼后的數據(yuv)AVFrame *frame = nullptr;// 獲取解碼器//    codec = avcodec_find_decoder_by_name("h264");codec = avcodec_find_decoder(AV_CODEC_ID_H264);if (!codec) {qDebug() << "decoder not found";return;}// 初始化解析器上下文parserCtx = av_parser_init(codec->id);if (!parserCtx) {qDebug() << "av_parser_init error";return;}// 創建上下文ctx = avcodec_alloc_context3(codec);if (!ctx) {qDebug() << "avcodec_alloc_context3 error";goto end;}// 創建AVPacketpkt = av_packet_alloc();if (!pkt) {qDebug() << "av_packet_alloc error";goto end;}// 創建AVFrameframe = av_frame_alloc();if (!frame) {qDebug() << "av_frame_alloc error";goto end;}// 打開解碼器ret = avcodec_open2(ctx, codec, nullptr);if (ret < 0) {ERROR_BUF(ret);qDebug() << "avcodec_open2 error" << errbuf;goto end;}// 打開文件if (!inFile.open(QFile::ReadOnly)) {qDebug() << "file open error:" << inFilename;goto end;}if (!outFile.open(QFile::WriteOnly)) {qDebug() << "file open error:" << out.filename;goto end;}// 讀取文件數據do {inLen = inFile.read(inDataArray, IN_DATA_SIZE);// 設置是否到了文件尾部inEnd = !inLen;// 讓inData指向數組的首元素inData = inDataArray;// 只要輸入緩沖區中還有等待進行解碼的數據while (inLen > 0 || inEnd) {// 到了文件尾部(雖然沒有讀取任何數據,但也要調用av_parser_parse2,修復bug)// 經過解析器解析ret = av_parser_parse2(parserCtx, ctx,&pkt->data, &pkt->size,(uint8_t *) inData, inLen,AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);if (ret < 0) {ERROR_BUF(ret);qDebug() << "av_parser_parse2 error" << errbuf;goto end;}// 跳過已經解析過的數據inData += ret;// 減去已經解析過的數據大小inLen -= ret;qDebug() << inEnd << pkt->size << ret;// 解碼if (pkt->size > 0 && decode(ctx, pkt, frame, outFile) < 0) {goto end;}// 如果到了文件尾部if (inEnd) break;}} while (!inEnd);// 刷新緩沖區//    pkt->data = nullptr;//    pkt->size = 0;//    decode(ctx, pkt, frame, outFile);decode(ctx, nullptr, frame, outFile);// 賦值輸出參數out.width = ctx->width;out.height = ctx->height;out.pixFmt = ctx->pix_fmt;// 用framerate.num獲取幀率,并不是time_base.denout.fps = ctx->framerate.num;end:inFile.close();outFile.close();av_packet_free(&pkt);av_frame_free(&frame);av_parser_close(parserCtx);avcodec_free_context(&ctx);// bug fix
// https://patchwork.ffmpeg.org/project/ffmpeg/patch/tencent_609A2E9F73AB634ED670392DD89A63400008@qq.com///
//    while ((inLen = inFile.read(inDataArray, IN_DATA_SIZE)) > 0)
//        while (inLen > 0) {
//            // 經過解析器解析
//            ret = av_parser_parse2(parserCtx, ctx,
//                                   &pkt->data, &pkt->size,
//                                   (uint8_t *) inData, inLen,
//                                   AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);//            if (ret < 0) {
//                ERROR_BUF(ret);
//                qDebug() << "av_parser_parse2 error" << errbuf;
//                goto end;
//            }//            // 跳過已經解析過的數據
//            inData += ret;
//            // 減去已經解析過的數據大小
//            inLen -= ret;//            // 解碼
//            if (pkt->size > 0 && decode(ctx, pkt, frame, outFile) < 0) {
//                goto end;
//            }
//        }
//    }
}void H264DncodeThread::run()
{VideoDecodeSpec out;out.filename = "E:/media/out-yuv420p-decode.yuv";h264Decode("E:/media/out-yuv420p.h264", out);qDebug() << out.width << out.height<< out.fps << av_get_pix_fmt_name(out.pixFmt);
}

線程調用:

void MainWindow::on_pushButton_h264_decode_clicked()
{m_pH264DncodeThread=new H264DncodeThread(this);m_pH264DncodeThread->start();
}

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

	H264DncodeThread *m_pH264DncodeThread=nullptr;

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


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

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

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

相關文章

【論文閱讀筆記】Emu Edit: Precise Image Editing via Recognition and Generation Tasks

【論文閱讀筆記】Emu Edit: Precise Image Editing via Recognition and Generation Tasks 論文閱讀筆記論文信息摘要背景方法結果額外 關鍵發現作者動機相關工作1. 使用輸入和編輯圖像的對齊和詳細描述來執行特定的編輯2. 另一類圖像編輯模型采用輸入掩碼作為附加輸入 。3. 為…

鴻蒙4.0開發筆記之ArkTs語言基礎與基本組件結構(四)

文章聲明&#xff1a;本文關于HarmonyOS系統的部分內容和描述借鑒于華為官網的“HarmonyOS開發者學堂”&#xff0c;有需要的也可以進入官網查看。<HarmonyOS第一課>ArkTS開發語言介紹 一、ArkTs語言介紹 ArkTS是鴻蒙系統&#xff08;HarmonyOS&#xff09;優選的主力應…

設計模式-創建型模式-工廠方法模式

一、什么是工廠方法模式 工廠模式又稱工廠方法模式&#xff0c;是一種創建型設計模式&#xff0c;其在父類中提供一個創建對象的方法&#xff0c; 允許子類決定實例化對象的類型。工廠方法模式是目標是定義一個創建產品對象的工廠接口&#xff0c;將實際創建工作推遲到子類中。…

解讀可解釋性機器學習:理解解釋性基準模型(EBM)

解讀可解釋性機器學習&#xff1a;理解解釋性基準模型&#xff08;EBM&#xff09; 近年來&#xff0c;隨著機器學習模型的復雜性不斷增加&#xff0c;研究人員和從業者對模型的可解釋性提出了更高的要求。可解釋性機器學習&#xff08;Explainable Machine Learning, XAI&…

SHAP - 機器學習模型可解釋性工具

github地址&#xff1a;shap/docs/index.rst at master shap/shap (github.com) SHAP使用文檔&#xff1a;歡迎使用 SHAP 文檔 — SHAP 最新文檔 SHAP介紹 SHAP&#xff08;SHapley Additive exPlanations&#xff09;是一種用于解釋預測結果的方法&#xff0c;它基于Shapley…

實現el-input-number數字框帶單位

實現的效果展示&#xff0c;可以是前綴單位&#xff0c;也可以是后綴單位。實現的思路就是動態修改偽元素 ::before 和 ::after 的 content值 實現二次封裝數字框的代碼如下&#xff1a; <template><el-input-numberref"inputNumber"v-model"inputVal…

opencv-直方圖

直方圖是一種對圖像亮度分布的統計表示&#xff0c;它顯示了圖像中每個灰度級別的像素數量。在OpenCV中&#xff0c;你可以使用cv2.calcHist() 函數計算直方圖。 以下是一個簡單的示例&#xff0c;演示如何計算和繪制圖像的直方圖&#xff1a; import cv2 import numpy as np …

【C++容器】優先級隊列 仿函數 反向迭代器

優先級隊列&#xff0c;仿函數&#xff0c;反向迭代器 優先級隊列認識優先級隊列模擬實現優先級隊列 淺談仿函數仿函數的大致了解仿函數的實現 反向迭代器什么是反向迭代器&#xff1f;反向迭代器的實現 結語 優先級隊列 認識優先級隊列 優先級隊列&#xff08;priority_queue…

Doris分區與分桶(八)

接上篇----------Doris 建表示例 Doris 支持兩層的數據劃分。第一層是 Partition&#xff0c;支持 Range 和 List 的劃分方式。第二層是 Bucket&#xff08;Tablet&#xff09;&#xff0c;僅支持 Hash 的劃分方式。 也可以僅使用一層分區。使用一層分區時&#xff0c;只支持…

低成本打造便攜式無線網絡攻防學習環境

1.摘要 一直以來, 無線網絡安全問題與大眾的個人隱私息息相關, 例如: 為了節省流量, 連接到一個看似安全的免費WiFi, 在使用過程中泄露自己的各類密碼信息甚至銀行卡賬號密碼信息。隨著家用智能電器的普及, 家中的各類智能設備連入家里的無線網絡, 卻突然失靈, 甚至無法正常連…

模擬Spring源碼思想,手寫源碼,理解注解

1、BeanDefinition package com.csdn.myspring; import lombok.AllArgsConstructor; import lombok.Data; Data AllArgsConstructor public class BeanDefinition {private String beanName;private Class beanClass; }2、掃描包的工具類MyTools package com.csdn.myspring; im…

@Scheduled注解 定時任務講解

用于在Java Spring框架中定時執行特定任務的注解 Scheduled&#xff0c;它能夠指定方法在特定時間間隔或特定時間點執行。默認參數是cron&#xff0c;cron參數被用來定義一個Cron表達式&#xff0c;它代表了任務執行的時間規則 參數如下 Cron 這是是一種時間表達式&#xff…

【應用程序啟動過程-三種加載控制器的方式-上午內容復習 Objective-C語言】

一、我們先來回憶一下,上午所有內容 1.首先呢,我們先說的是這個“應用程序啟動過程”, 應用程序啟動過程里面,有三方面內容 1)UIApplication對象介紹 2)AppDelegate對象介紹 3)應用程序啟動過程 現在不知道大家對這個應用程序啟動過程有印象嗎, 2.首先,這個UIAp…

MySQL數據庫時間計算的用法

今天給大家分享如何通過MySQL內置函數實現時間的轉換和計算&#xff0c;在工作當中&#xff0c;測試人員經常需要查詢數據庫表的日期時間&#xff0c;但發現開發人員存入數據庫表的形式都是時間戳形式&#xff0c;不利于測試人員查看&#xff0c;測試人員只能利用工具對時間戳進…

【 順序表經典算法—移除元素和合并兩個有序數組】

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 目錄 前言 經典算法OJ題1&#xff1a; 移除元素 解法一、逐個判斷 解法二、雙指針覆蓋 經典算法OJ題2&#xff1a; 合并兩個有序數組 OJ題分為兩個類型&#xff1a; 總結 前言…

MAX/MSP SDK學習07:list傳遞

實現自定義Obejct&#xff0c;要求將傳入的一組數據100后傳出。 #include "ext.h" #include "ext_obex.h" typedef struct _listTrans {t_object ob;void* outLet;t_atom* fArr;long listNum;} t_listTrans;void* listTrans_new(t_symbol* s, long arg…

14.Python 模塊

目錄 1. 使用模塊2. 使用包3. 常用模塊3.1 日期和時間3.2 偽隨機數3.3 摘要算法3.4 JSON 處理3.5 圖像處理 模塊是Python用來組織代碼的一種方法&#xff0c;包是Python用來組織模塊的一種方法。 1. 使用模塊 Python 把能夠相互包含&#xff0c;且有組織的代碼段稱為模塊&…

.NET面試題1

1.什么是C#&#xff1f; C#&#xff08;讀作"C sharp"&#xff09;是一種通用的、面向對象的編程語言&#xff0c;由Microsoft開發。它是一種靜態類型語言&#xff0c;支持強類型檢查和面向對象編程&#xff08;OOP&#xff09;的概念。C#主要用于開發Windows應用程序…

Bug等級劃分

Bug是指在程序或系統中存在的錯誤、缺陷或異常&#xff0c;是由于編碼錯誤、設計問題、邏輯錯誤或其他因素導致的。 常見的Bug分類方法 功能性Bug與軟件的功能有關&#xff0c;軟件無法正常工作、功能與需求不符或功能執行不正確。 用戶界面Bug與軟件的用戶界面有關&#xff…

Unity中Shader雙向反射分布函數BRDF

文章目錄 前言一、渲染方程二、什么是BxDF1、BSSRDF2、BRDF3、BTDF4、BSDF 三、迪士尼原則的BRDF四、迪士尼原則的BRDF的參數五、在Unity中看一下默認Shader的這些參數六、在這里記錄一下使用 Blender 和 SubstancePainter 的流程1、在Blender中導出模型為 .obj 格式2、在Subst…