int main(int argc, char *argv[])
{testtread tt;tt.init();QApplication a(argc, argv);Xplay2 w;w.show();w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);tt.video = w.ui.openGLWidget;tt.start();return a.exec();
}

在实战14中,是直接读取的yuv文件然后用OpenGL进行绘制:
fp = fopen(“out240x128.yuv”, “rb”);
这里我们是利用解码获得的frame来进行绘制

打开.ui文件,添加OpenGL控件:

提升为类xvideowidget:

在ui_Xplay2文件中可以看到如下代码:

class Ui_Xplay2Class
{public:xvideowidget *openGLWidget;void setupUi(QWidget *Xplay2Class){if (Xplay2Class->objectName().isEmpty())Xplay2Class->setObjectName(QString::fromUtf8("Xplay2Class"));Xplay2Class->resize(1072, 790);openGLWidget = new xvideowidget(Xplay2Class);openGLWidget->setObjectName(QString::fromUtf8("openGLWidget"));openGLWidget->setGeometry(QRect(149, 129, 800, 600));retranslateUi(Xplay2Class);QMetaObject::connectSlotsByName(Xplay2Class);} // setupUivoid retranslateUi(QWidget *Xplay2Class){Xplay2Class->setWindowTitle(QCoreApplication::translate("Xplay2Class", "Xplay2", nullptr));} // retranslateUi};

可以看到xvideowidget *openGLWidget;在这个界面的大类里放了个指向xvideowidget的指针OpenGLwidget,并用该指针调用resize等方法

在代码中添加xvideowidget.h:

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>
#include <mutex>
struct AVFrame;
class xvideowidget : public QOpenGLWidget, protected QOpenGLFunctions
{Q_OBJECTpublic:void Init(int width, int height);//不管成功与否都释放frame空间virtual void Repaint(AVFrame* frame);xvideowidget(QWidget* parent);~xvideowidget();
protected://刷新显示void paintGL();//初始化glvoid initializeGL();// 窗口尺寸变化void resizeGL(int width, int height);
private:std::mutex mux;//shader程序QGLShaderProgram program;//shader中yuv变量地址GLuint unis[3] = { 0 };//openg的 texture地址GLuint texs[3] = { 0 };//材质内存空间unsigned char* datas[3] = { 0 };int width = 0;int height = 0;
};

xvideowidget.cpp与实战14中不同的是实战14中将宽与高是提前定死的,而这里根据传进来的数据来设定宽高,并提供了一个新接口,目的是设置宽高,分配材质内存空间,设置放大缩小方式:

void xvideowidget::Init(int width, int height)
{mux.lock();this->width = width;this->height = height;delete datas[0];delete datas[1];delete datas[2];///分配材质内存空间datas[0] = new unsigned char[width * height];     //Ydatas[1] = new unsigned char[width * height / 4];   //Udatas[2] = new unsigned char[width * height / 4];   //Vif (texs[0]){glDeleteTextures(3, texs);}//创建材质glGenTextures(3, texs);//YglBindTexture(GL_TEXTURE_2D, texs[0]);//放大过滤,线性插值   GL_NEAREST(效率高,但马赛克严重)glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//UglBindTexture(GL_TEXTURE_2D, texs[1]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);//VglBindTexture(GL_TEXTURE_2D, texs[2]);//放大过滤,线性插值glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//创建材质显卡空间glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);mux.unlock();
}

因为创建材质也用到高和宽,所以也放到这个接口中
创建材质显卡空间要用到tex,删除也会删tex,为了防止用到一半被删掉导致程序宕掉,加个锁,其他函数用到data与tex的也要加锁,对于repaint()这种频繁出现的,要注意加锁的代码量,会影响性能,对于init这种只出现一次的无所谓

读与绘制会阻塞,因此使用QThread:

class testtread :public QThread
{public:void init(){const char* path = "E:\\ffmpeg\\test.mp4";const char* url = "rtsp://27.22.78.122:8554/1";cout << "demux.Open = " << demux.Open(path) << endl;cout << "vdecode.open()" << vdecode.open(demux.CopyVPara()) << endl;cout << "adecode.open()" << adecode.open(demux.CopyAPara()) << endl;}void run(){for (;;){AVPacket* pkt = demux.readfz();if (demux.isvideo(pkt) == true){vdecode.send(pkt);AVFrame* frame = vdecode.receive();//cout << "视频解码" <<frame<< endl;video->Repaint(frame);Sleep(40);}else{//adecode.send(pkt);//AVFrame* frame = adecode.receive();//cout << "音频解码" <<frame<< endl;}if (!pkt)break;}}xdemux demux;xvideowidget* video;
protected:xdecode vdecode;xdecode adecode;};

因为主线程退出后video被删了,然而该线程还在,所以会出点小问题,后面再解决
main函数:

int main(int argc, char *argv[])
{testtread tt;tt.init();QApplication a(argc, argv);Xplay2 w;w.show();w.ui.openGLWidget->Init(tt.demux.width, tt.demux.height);tt.video = w.ui.openGLWidget;tt.start();return a.exec();
}

1.实例化一个线程,
实例化线程的同时会实例化demux,vdecode,adecode,xvideowidget*,并将解封装后的视频信息传给vdecode,音频信息传给adecode

2.打开一个QT的窗口

3.将解封装得到的宽高信息传给ui窗口里添加的控件的初始化函数,让QT窗口上可以显示一个与我们的媒体文件同样宽高的视频窗口,只不过不能显示画面
tt的demux与video,w的ui都为类外访问,所以要把这些成员开放出去设为public

4.让线程中的指向xvideowidget的指针指向我们添加的控件,调用start即调用线程的run,在run里将解码得到的packet发给openg进行绘制并显示在控件上

void xvideowidget::Repaint(AVFrame* frame)
{if (!frame){qDebug() << "show failed1" ;return;}mux.lock();//容错,保证尺寸正确if (!datas[0] || width * height == 0 || frame->width != this->width || frame->height != this->height){av_frame_free(&frame);mux.unlock();qDebug() << "show failed2";return;}memcpy(datas[0], frame->data[0], width * height);memcpy(datas[1], frame->data[1], width * height / 4);memcpy(datas[2], frame->data[2], width * height / 4);//行对齐问题mux.unlock();//刷新显示update();qDebug()<< "repaint" ;
}

运行情况如下:

播放器实战17 xvideowidget相关推荐

  1. 播放器实战28 总结

    至此,播放器的基本功能已经实现,进行一个总结: 一,仅进行播放时的函数调用流程 只做一个大致的梳理且不涉及seek等操作): 01.QT中的整个控件为QWidget类,Xplay2类为其继承,在mai ...

  2. 基于 Vue 的直播播放器实战

    原文地址:点击进入 前言 时下直播的盛行让很多人对直播技术产生浓厚的兴趣,orange 本人也不例外,本文借着实战的目的完成一个 demo,并没有深入的讲解直播技术的实现原理以及推流和拉流的实现,为什 ...

  3. vue实现音乐播放器实战笔记

    一.项目说明 该播放器的是基于学习vue的实战练习,不用于其他途径.应用中的全部数据来自于 QQ音乐 移动端(https://m.y.qq.com/),利用 jsonp 以及 axios 代理后端请求 ...

  4. 播放器实战19 Xaudio打开音频

    1.xaudio.h #pragma once class xaudioplay {public:static xaudioplay* get();xaudioplay();//一定得是虚析构函数,d ...

  5. vue 判断同一数组内的值是否一直_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  6. 妙味课堂H5音乐播放器实战视频课程 ajax实战教程

    课程介绍: 本次课程涉及的知识点包括移动端H5.CSS3.JS.滑屏.HTTP协议.AJAX.跨域.前后端交互.PHP.mySql.jQuery--配合这些知识点,讲师写了一个H5播放器demo,用来 ...

  7. 后端实体类接收数组_前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目...

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  8. 前端代码+后端API,值得一学的Vue高仿音乐播放器实战项目

    项目名称:vue-fds_music 项目作者:符道胜 开源许可协议:Apache-2.0 项目地址:https://gitee.com/fudaosheng/vue-fds_music 项目简介 V ...

  9. 播放器实战22 解决花屏与卡顿问题

    1.内存对齐 1.1什么是内存对齐 在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int.long.float等)的变量,也可以是一些复合数据类型(如数组.结构.联合等)的数据 ...

最新文章

  1. Bug tracker .net 部署经验(完善中)
  2. 干货丨吴恩达深度学习课程的思维导图总结
  3. 举例讲清楚模型树和回归树的区别
  4. C#2.0新特性探究之模拟泛型和内置算法
  5. vue 打包后本地先自己启动服务 anywhere 非常好用
  6. 英雄由此诞生------直击微软2008发布大会
  7. OpenTSDB的读写API
  8. 网银安全控件远程代码执行漏洞分析
  9. 快速学会普源示波器的调节和使用
  10. world2016论文脚注问题
  11. uni-app开发模式中的选择图片(uni.chooseImage)、上传图片(uni.uploadFile)、图片预览(uni.previewImage)
  12. 基于Python热点新闻关键词数据分析系统
  13. 计算机自动计算的条件,电脑表格怎样自动计算
  14. Webpack--模块热替换(HMR)
  15. 数字经济的发展需要包括区块链在内的八大技术的支撑360云储
  16. 如何写英文科技论文 papers
  17. 中英文互译之Excel表格
  18. 常数和基本初等函数的导数
  19. 用C语言实现一个函数,判断一个数是不是素数
  20. 【windows】实战部署一(安装)SVNserver服务端+SVNclient客户端

热门文章

  1. 爬虫与云服务器云数据库
  2. 七年级安全的使用计算机,七年级安全教育教案
  3. 【已解决】如何使用Intel® oneAPI HPC Toolkit中的Fortran编译器ifort?
  4. ZABBIX监控DM数据库
  5. JS实现页面快速定位
  6. termux获取sd卡读写权限_重回SD市场 三星128GB/256GB PRO Plus存储卡评测
  7. 教女朋友学习 vue的生命周期钩子函数
  8. 旗帜软件工作室Java第二阶段考核答案
  9. MVCC详解,深入浅出简单易懂
  10. [转]战地3寒霜2引擎详解:物件光照效果技术特性