x86平臺基于Qt+opengl優化ffmpeg軟解碼1080P視頻渲染效率

一般的在arm嵌入式平臺,大多數板子都要硬解碼硬件渲染的框架,使用即可。

在x86下比較麻煩了。

優化的思路一共有以下幾個方面,

1. 軟解碼變成硬解碼

2. 將YUV轉QImage的操作轉移到GPU

3. QWidget渲染QImage變成opengGL渲染AVFrame

這三點優化來說2與3是優化的效率是非常顯著的。

1的優化效果往往需要將硬解碼的數據copy至CPU再使用2-3的優化。

這樣一來,解碼效率提升了,但是數據copy時候CPU使用率會上升。如果兩者抵消后CPU使用率還是上升那就得不償失。如果能實現硬解碼的數據不經過CPU直接打到GPU進行渲染,那就是最完美的方案。這個在x86下需要研究opengl渲染硬件類型數據,難度未知,理論如果用的是比較新的框架,資料會多一些。

本文主要是基于2-3的優化,在qt5.1下面基于opengl實現了這個方案,在多路1080P的使用場景下CPU使用率下降非常明顯。

#include "opengl_yuv_shader.h"
#include <QDebug>
#include <iostream>
#include <GL/gl.h>
#include <QGLShader>opengl_yuv_shader::opengl_yuv_shader(QWidget *parent) : QGLWidget(parent), useVBO(false),vboId(0),yuv420p_shaderProgram(0),yuvj422p_shaderProgram(0)
{textures[0]=0;textures[1]=0;textures[2]=0;av_frame = nullptr;connect(this,SIGNAL(render_frame()),this,SLOT(slot_render_frame()),Qt::QueuedConnection);//5 lu 60% cpu
}opengl_yuv_shader::~opengl_yuv_shader() {makeCurrent();glDeleteTextures(3, textures);if (yuv420p_shaderProgram) {glDeleteProgram(yuv420p_shaderProgram);}if (yuvj422p_shaderProgram) {glDeleteProgram(yuvj422p_shaderProgram);}doneCurrent();
}void opengl_yuv_shader::initTextures()
{glGenTextures(3, textures);for (int i = 0; i < 3; ++i) {glBindTexture(GL_TEXTURE_2D, textures[i]);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);glBindTexture(GL_TEXTURE_2D, 0);}
}void opengl_yuv_shader::initShaders()
{QGLShader *vshader = new QGLShader(QGLShader::Vertex, this);const char *vsrc ="attribute vec4 vertex;\n""attribute vec2 texCoord;\n""varying vec2 texc;\n""void main(void)\n""{\n""    gl_Position = vertex;\n""    texc = texCoord;\n""}\n";vshader->compileSourceCode(vsrc);//編譯頂點著色器代碼QGLShader *fshader = new QGLShader(QGLShader::Fragment, this);//vec4(1.0,0,0,1.0);const char *fsrc ="uniform sampler2D texture;\n""varying vec2 texc;\n""void main(void)\n""{\n""    gl_FragColor =  texture2D(texture,texc);\n""}\n";//本方案的核心點在于這個片段著色器,在GPU上完成YUV轉RGB的浮點運算。//由于測試的攝像機是基于YUV J420P轉換的所以算法上與YUV420P略有差別。// 實際使用需要根據具體的AVFrame格式,進行轉換。可初始化多個SHADER管理器、// 渲染時,根據像素格式選擇shader渲染const char* fragmentShaderSource = R"(varying vec2 texc;uniform sampler2D textureY;uniform sampler2D textureU;uniform sampler2D textureV;void main(){float y = texture2D(textureY, texc).r;float u = texture2D(textureU, texc).r;float v = texture2D(textureV, texc).r;float r = y + 1.402 * (v - 0.5);float g = y - 0.344136 * (u - 0.5) - 0.714136 * (v - 0.5);float b = y + 1.772 * (u - 0.5);// 確保 RGB 值在 0-1 范圍內r = clamp(r, 0.0, 1.0);g = clamp(g, 0.0, 1.0);b = clamp(b, 0.0, 1.0);gl_FragColor = vec4(r, g, b, 1.0);})";fshader->compileSourceCode(fragmentShaderSource); //編譯紋理著色器代碼program.addShader(vshader);//添加頂點著色器program.addShader(fshader);//添加紋理碎片著色器program.bindAttributeLocation("vertex", 0);//綁定頂點屬性位置program.bindAttributeLocation("texCoord", 1);//綁定紋理屬性位置// 鏈接著色器管道if (!program.link()){close();qDebug()<<"program.link() error"<<endl;}// 綁定著色器管道if (!program.bind()){close();qDebug()<<"program.bind() error"<<endl;}
}void opengl_yuv_shader::initializeGL()
{initializeOpenGLFunctions();glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glEnable(GL_TEXTURE_2D);initTextures();initShaders();
//    glDisable(GL_DEPTH_TEST);
//    glDisable(GL_CULL_FACE);
//    glDisable(GL_BLEND);const GLubyte* renderer = glGetString(GL_RENDERER);const GLubyte* vendor = glGetString(GL_VENDOR);const GLubyte* version = glGetString(GL_VERSION);const GLubyte* glslVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);std::cout << "Renderer: " << renderer<<std::endl;std::cout << "Vendor: " << vendor<<std::endl;std::cout << "OpenGL Version: " << version<<std::endl;std::cout << "GLSL Version: " << glslVersion<<std::endl;texCoords.append(QVector2D(0, 1)); //左上texCoords.append(QVector2D(1, 1)); //右上texCoords.append(QVector2D(0, 0)); //左下texCoords.append(QVector2D(1, 0)); //右下//頂點坐標vertices.append(QVector3D(-1, -1, 1));//左下vertices.append(QVector3D(1, -1, 1)); //右下vertices.append(QVector3D(-1, 1, 1)); //左上vertices.append(QVector3D(1, 1, 1));  //右上
}void opengl_yuv_shader::resizeGL(int w, int h)
{qDebug() << "Oopengl_yuv_shader::resizeGL w=" << w<<endl;glViewport(0, 0, w, h);glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);glMatrixMode(GL_MODELVIEW);
}void opengl_yuv_shader::paintGL()
{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);render_lock.lock();if (!av_frame) {render_lock.unlock();return;}glEnable(GL_TEXTURE_2D);program.enableAttributeArray(0);//啟用頂點屬性0,也就是渲染平面的頂點坐標program.enableAttributeArray(1);//啟用頂點屬性1,也就是渲染平面的紋理坐標//紋理坐標的和頂點的對應關系完成渲染program.setAttributeArray(0, vertices.constData() );program.setAttributeArray(1, texCoords.constData()  );if(av_frame->format == AV_PIX_FMT_YUV420P || av_frame->format == AV_PIX_FMT_YUVJ420P  ){if (av_frame&&av_frame->data[0]) {glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, textures[0]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, av_frame->width, av_frame->height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, av_frame->data[0]);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, textures[1]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, av_frame->width/2, av_frame->height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, av_frame->data[1]);glActiveTexture(GL_TEXTURE2);glBindTexture(GL_TEXTURE_2D, textures[2]);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, av_frame->width/2, av_frame->height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, av_frame->data[2]);program.setUniformValue("textureY", 0);program.setUniformValue("textureU", 1);program.setUniformValue("textureV", 2);}}render_lock.unlock();// 繪制glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);}void opengl_yuv_shader::set_yuv_frame(AVFrame *frame)
{// 1. 如果 av_frame 已經存在,先釋放它render_lock.lock();if (av_frame) {av_frame_free(&av_frame);av_frame = nullptr;}// 2. 深拷貝 AVFrameav_frame = av_frame_clone(frame);if (!av_frame) {av_log(NULL, AV_LOG_ERROR, "Failed to clone frame\n");render_lock.unlock();return;}render_lock.unlock();emit render_frame();}void opengl_yuv_shader::slot_render_frame()
{update();
}

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

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

相關文章

ocr智能票據識別系統|自動化票據識別集成方案

在企業日常運營中&#xff0c;對大量票據實現數字化管理是一項耗時且容易出錯的任務。隨著技術的進步&#xff0c;OCR&#xff08;光學字符識別&#xff09;智能票據識別系統的出現為企業提供了一個高效、準確的解決方案&#xff0c;不僅簡化了財務流程&#xff0c;還大幅提升了…

docker批量pull/save/load/tag/push鏡像shell腳本

目錄 注意&#xff1a; 腳本內容 執行效果 注意&#xff1a; 以下腳本為shell腳本通過docker/nerdctl進行鏡像獨立打包鏡像的相關操作腳本內倉庫信息和鏡像存取路徑需自行更改需自行創建images.txt并填寫值&#xff0c;并且與腳本位于同級目錄下 [rootmaster01 sulibao]# l…

利用Java爬蟲精準獲取商品銷量詳情:實戰案例指南

在電商領域&#xff0c;商品銷量數據是衡量產品受歡迎程度和市場表現的關鍵指標。精準獲取商品銷量詳情不僅能幫助商家優化產品策略&#xff0c;還能為市場研究和數據分析提供豐富的數據資源。本文將詳細介紹如何利用Java爬蟲技術精準獲取商品銷量詳情&#xff0c;并分享關鍵技…

30 款 Windows 和 Mac 下的復制粘貼軟件對比

在日常電腦操作中&#xff0c;復制粘貼是極為高頻的操作&#xff0c;一款好用的復制粘貼軟件能極大提升工作效率。以下為你詳細介紹 30 款 Windows 和 Mac 下的復制粘貼軟件&#xff0c;并對比它們的優缺點&#xff0c;同時附上官網下載地址&#xff0c;方便大家獲取軟件。 Pa…

【Linux】Linux 文件系統——有關 inode 不足的案例

??大家好&#xff0c;我是練小杰&#xff0c;今天周二了&#xff0c;明天星期三&#xff0c;還有三天就是星期五了&#xff0c;堅持住啊各位&#xff01;&#xff01;&#xff01;&#x1f606; 本文是對之前Linux文件權限中的inode號進行實例討論&#xff0c;看到博客有錯誤…

WPF快速創建DeepSeek本地自己的客戶端-基礎思路版本

開發工具&#xff1a;VS 2015 開發環境&#xff1a;.Net 4.0 使用技術&#xff1a;WPF 本篇文章內容&#xff1a; 本地部署DeepSeek以后一般使用網頁工具&#xff08;如Chatbox&#xff09;或者DOS窗口與其對話。本篇文章使用WPF創建一個基礎版的對話工具。 一、搭建本地DeepS…

VSCode本地python包“無法解析導入”

問題現象 在使用 VSCode 編寫 Python 代碼時&#xff0c;雖然程序能正常運行&#xff0c;但遇到“無法解析導入”的問題&#xff0c;導致代碼無法高亮。 解決方法 配置 python.autoComplete.extraPaths 打開 VSCode 設置&#xff08;CtrlShiftP -> Preferences: Open Wo…

目標檢測IoU閾值全解析:YOLO/DETR模型中的精度-召回率博弈與工程實踐指南

一、技術原理與數學本質 IoU計算公式&#xff1a; IoU \frac{Area\ of\ Overlap}{Area\ of\ Union} \frac{A ∩ B}{A ∪ B}閾值選擇悖論&#xff1a; 高閾值&#xff08;0.6-0.75&#xff09;&#xff1a;減少誤檢&#xff08;FP↓&#xff09;但增加漏檢&#xff08;FN↑…

藍橋杯備考:二分算法之木材加工

P2440 木材加工 - 洛谷 這種題我們就是把答案枚舉出來&#xff0c;然后對答案進行二分&#xff0c;然后再進行判斷 比如我們這道題&#xff0c;我們枚舉切割的長度&#xff0c;然后由于切割長度越長切割段數越少 切割長度越短&#xff0c;切割段數越多的性質&#xff0c;我們…

Mongodb數據管理

Mongodb數據管理 1.登錄數據庫&#xff0c;查看默認的庫 [rootdb51~]# mongo> show databases; admin 0.000GB config 0.000GB local 0.000GB> use admin switched to db admin > show tables system.version > admin庫&#xff1a;admin 是 MongoDB 的管理…

QT基礎七、用純代碼編寫界面

終于迎來了界面開發的實戰環節&#xff01;今天我們將通過純代碼的方式&#xff0c;親手打造一個界面。如果你對 Qt 感興趣&#xff0c;歡迎訂閱我的 Qt 基礎入門專欄 &#xff08;完全免費哦&#xff09;。雖然前面幾篇文章主要是基礎知識講解&#xff0c;可能會顯得稍微平淡&…

我用AI做數據分析之數據清洗

我用AI做數據分析之數據清洗 AI與數據分析的融合效果怎樣&#xff1f; 這里描述自己在使用AI進行數據分析&#xff08;數據清洗&#xff09;過程中的幾個小故事&#xff1a; 1. 變量名的翻譯 有一個項目是某醫生自己收集的數據&#xff0c;變量名使用的是中文&#xff0c;分…

C++11 thread

文章目錄 C11 線程庫線程對象的構造方式無參的構造函數調用帶參的構造函數調用移動構造函數thread常用成員函數 this_thread命名空間join && detachmutex C11 線程庫 線程對象的構造方式 無參的構造函數 1、調用無參的構造函數,調用無參的構造函數創建出來的線程對象…

List<Map<String, Object>> 如何對某個字段求和

在Java中&#xff0c;如果你有一個List<Map<String, Object>>的結構&#xff0c;并且你想要對某個特定字段進行求和&#xff0c;你可以使用Java 8的Stream API來簡化這個過程。下面是一個示例代碼&#xff0c;演示如何對某個字段進行求和。 假設你有一個List<M…

Linux 固定 IP 地址和網關

Linux 固定 IP 地址和網關 查看 IP ifconfig ifconfig eth0 ip addr ip addr show eth0 查看網關 ip route show route -n netstat -rn 設置固定 IP // 配置靜態IP文件/etc/network/interfaces $ vi /etc/network/interfacesauto eth0 iface eth0 inet static addre…

移動通信發展史

概念解釋 第一代網絡通信 1G 第二代網絡通信 2G 第三代網絡通信 3G 第四代網絡通信 4G 4g網絡有很高的速率和很低的延時——高到500M的上傳和1G的下載 日常中的4G只是用到了4G技術 運營商 移動-從民企到國企 聯通-南方教育口有人 電信 鐵通&#xff1a;成立于 2000 年…

進階數據結構——樹狀數組

前言 看這篇文章前我建議你們先看這個視頻還有這個視頻&#xff0c;不然你們可能看不懂。 一、樹狀數組的核心思想與本質 核心思想&#xff1a;樹狀數組&#xff08;Fenwick Tree&#xff09;是一種用于高效處理前綴和查詢和單點更新的數據結構。 本質&#xff1a;通過二進…

LabVIEW無刷電機控制器檢測系統

開發了一種基于LabVIEW的無刷電機控制器檢測系統。由于無刷電機具有高效率、低能耗等優點&#xff0c;在電動領域有取代傳統電機的趨勢&#xff0c;而無刷電機的核心部件無刷電機控制器產量也在不斷增長。然而&#xff0c;無刷電機控制器的出廠檢測仍處于半自動化狀態&#xff…

STM32 CAN過濾器配置和應用方法介紹

目錄 概述 一、CAN過濾器核心概念 二、過濾器配置步驟&#xff08;以標準ID為例&#xff09; 三、不同模式的配置示例 四、高級配置技巧 五、調試與問題排查 六、關鍵計算公式 總結 概述 在STM32微控制器中&#xff0c;CAN過濾器可以配置為標識符屏蔽模式和標識符列表模…

個人系統架構技術分享

架構技術 技術版本說明CentOS7.9操作系統Amoeba負責MySQL讀寫分離NFS分布式存儲ISCSI塊存儲keepalived日志收集MySQL5.7數據庫存儲MinIO8.4.5對象存儲Kubernetes1.23.15應用容器管理平臺Redis7.0分布式緩存Elasticsearch7.17.3搜索引擎nacos3.3.4服務注冊 后端技術 技術版本…