首页 > 其他分享 >基于FFmpeg和Qt实现简易视频播放器

基于FFmpeg和Qt实现简易视频播放器

时间:2023-11-25 18:56:47浏览次数:40  
标签:播放器 视频 FFmpeg 控件 解码 线程 播放 Qt

VideoPlay001

记得一键三连哦

  • 使用qt+ffmpeg开发简单的视频播放器,无声音
  • 视频解码使用的是软解码即只用CPU进行QPainter绘制每一帧图像,CPU占用过高
  • image-20231119121201748
  • 简单易学,适合小白入门学习FFMpeg视频解析的基本API

遗留问题

  • 视频播放时间的处理,基匀速播放的实现原理

项目代码

videoPlay001分支

项目警告

  • 注:博主本人学习过程的分享,引用他人的文章皆会标注原作者
  • 注:点名某初生DN,未来是属于开源的
  • 注:本人文章非盈利性质,若有侵权请联系我删除
  • 注:联系方式Q:2950319782
  • 注:博主本人很菜,文章基本是二次创作,大佬请忽略我的随笔
  • 注:我会一步步分享实现的细节,若仍有问题请留言,还可以问ChatGPT

项目引用

问题解决

开发环境

  • 系统:Win10
  • Qt:5.14.2
  • 编译器:qtcreator 4.11.1, minGW64
  • ffmpeg: 5.12

实现功能

  • 使用ffmpeg音视频库软解码实现视频播放器
  • 支持打开多种本地视频文件(如mp4,mov,avi等)
  • 支持解析多种网络视频流(如rtsp,rtmp,http等)
  • 支持视频匀速播放
  • 采用QPainter进行图像显示,支持自适应窗口缩放
  • 视频播放支持实时开始,暂停,继续播放
  • 采用模块化编程,视频解码,线程控制,图像显示各功能分离,低耦合
  • 多线程编程

实现逻辑

  • 程序主逻辑
  • image-20231119121247974
  • ffmpeg软解码流程
  • ffmpeg

项目实现

项目结构

image-20231119121333432

项目思路

页面搭建

  • 需要实现视频的播放,那么要先要有个页面,使用qtcreator设计界面
  • 不是很复杂的页面我们直接使用自带的ui界面即可
  • image-20231120180634222
  • 博主使用的是minGW64编译
  • 我们要有一个combo box来获取网络视频流的URL或者本地视频流的地址
  • 还需要一个打开文件的按钮,来打卡文件对话框,选择视频文件
  • 还需要一个开始播放的按钮和一个暂停播放的按钮
  • 至于QPainter绘制解码出来的每一帧图片我们自定义一个PlayImage控件,来显示视频
  • PlayImage继承自Widget,记得把ui文件中的PlayImage控件提升为自定义的控件
  • 最终的ui图
  • image-20231120182308679

自定义控件

  • 一步步来,我们先实现自定义的控件来解决视频的功能
  • 先创建一个CPP类PlayImage继承自QWidget
  • 为什么不用QLabel显示图片呢,因为显示静态的图片还可以,但是如果像视频这样频繁的更新图片,会使程序变得异常卡顿,因此使用QPainter重绘每一帧图像来实现视频播放的功能
  • 这个Demo图片数据量比较小,完全可以实现,基本的逻辑就是不断更新图像路径,一直重绘,直到没有图像传进来
  • 其实这里自定义控件应该是单独封装的,作为外部文件引入,方便复用,但这里为了简单,还是直接写入代码吧
  • 在这里封装了两个主要的方法updateImage和updatePixmap,解码出的每一帧图片只需要调用对应的图像更新方法就可以实现视频显示

视频解码实现

  • 到这里,已经有视频播放的功能了,现在需要把视频的解码完成出来
  • 到这里呢,其实建议把视频解码封装成一个单独的功能,使用pri引入即可
  • 这里呢,直接创建一个不带ui文件的pri就可以,我是直接在源文件目录下新建了一个play文件了,新建一个videoplay.pri文件,再修改一下主工程的pro文件,引入即可
  • 在这个子工程中,添加一个纯cpp类,videoDocode,实现视频解码主要功能
  • 视频解码按照上面的流程图实现即可,当然需要先引入FFMpeg的l相关文件,这里建议以外部文件引入,我是放在videoplay.pri目录下,新建一个ffmpeg文件夹,再更改一下pri文件,引入即可
视频解码
  • 引入avformat解封装模块,先来把封装的格式剥去
  • 这里呢因为使用了FFmpeg,建议还是写c风格的代码,省的报错
  • 先定义一个通用的处理错误的函数errHandle
  • 然后在open函数中实现解析视频流,剥去封装格式,然后读取视频流获取信息
  • 然后我们发现需要手动释放一些资源,自己定义一个free函数,先释放解封装上下文,后续还需要释放什么资源自己添加到free函数里就可以了
  • 下面的小逻辑都在代码里以注释的形式表示了,不写了,太累了
  • 这里完了之后,其实就是把视频解码的功能封装好,供下面的读取线程调用,因为都写在子线程的run函数里太复杂了,所以这里单独处理视频解码
视频解码线程
  • 这里为什么需要有一个线程类呢,因为在qt设计中,窗口的控制和各种功能的后台实现应该是不同线程处理的,否则都给窗口线程处理,这个程序会变得异常卡顿
  • 直接创建一个readThread类继承自QThread类,这里基本是按照流程图调用视频解码的函数即可,并返回给窗口线程相应的值,下面要定义几个public的接口供窗口线程调用
  • 主要是处理重写run函数,在cpp文件中引入videoDocode,并实例化对象,调用视频解码功能
  • 先调用videoDocode的open函数,
  • 需要一个自定义信号playState来与窗口线程传递信息,处理播放状态
  • open成功后开始调用videoDocode的read函数
  • 还需要处理视频暂停pause的功能,这里需要先实现sleep延时操作
  • 视频解码是一个相对耗时的操作,不能影响窗口线程,因此解码线程应该是非阻塞延时
  • 成功open和read后,需要关闭线程close了
  • 下面我们来处理窗口线程

窗口线程

  • 在ui文件中绑定控件的槽函数
  • 通过将获取的文件路径显示在combox上,其他控件通过文本值调用,其实是不安全的
  • 页面的具体状态通过自定义的信号与槽与视频解码线程交互

标签:播放器,视频,FFmpeg,控件,解码,线程,播放,Qt
From: https://www.cnblogs.com/kanhai1024/p/17855871.html

相关文章

  • mqtt协议订阅消息
    本文采用mica-mqtt进行编写消息订阅客户端1.引入依赖<dependency><groupId>net.dreamlu</groupId><artifactId>mica-mqtt-client-spring-boot-starter</artifactId><version>2.0.3</version></dependency>2.配置信息(可在applicat......
  • 4-基因家族的系统进化树-基于Windows系统上的iqtree
    今天来讲如何构建系统进化树,使用的软件是iqtree,这是一个基于最大似然法估算的建树软件,可以在Windows系统上运行。1,于此网址“http://www.iqtree.org/”自行下载,并解压。2,将已经鉴定好的自己的基因家族蛋白序列(fasta格式),先用MAFFT网站做多序列比对。我的蛋白序列文件命名是“Ptb......
  • QT实战 之翻金币游戏
    QT实战之翻金币游戏相较于原版的优化:关卡数据不是用静态的config配置,而是动态生成,每次打开的关卡都生成不同的游戏数据,增加了可玩性;关卡数据依据关卡等级的不同而生成不同难度的数据,随关卡的增加而不断提升难度;金币矩阵由原版的4*4升级为5*5,增加了游戏难度;选择关卡按钮使用......
  • FFmpeg 音频重采样
    1.音频重采样1.1什么是重采样所谓的重采样,就是改变⾳频的采样率、sampleformat、声道数等参数,使之按照我们期望的参数输出。1.2为什么要重采样原有的⾳频参数不满⾜我们的需求,⽐如在FFmpeg解码⾳频的时候,不同的⾳源有不同的格式,采样率等,在解码后的数据中的这些参数也会不⼀......
  • 从UE虚幻引擎到播放器页面的通信
    在前面:https://www.cnblogs.com/makalochen/p/17803468.html#新建游戏模式我们已经实现了,从前端到UE的通信,那能不能UE主动给前端发送消息呢?就比如我在播放的像素流中点击了某个物体给所有页面发个消息,说你已经点击了某个物体答案是可以的,参考官网https://docs.unrealeng......
  • 【转载】Qt中的智能指针
    不用到处找了,附高质量博客链接Qt智能指针介绍:QSharedPointer、QWeakPointer、QScopedPointer、QPointer(附实例)-CSDN博客Qt智能指针信号槽连接问题_qtconnect智能指针_Jason~shen的博客-CSDN博客......
  • Qt之pro文件写法的详细介绍
    在Qt项目的.pro文件中,有一些特定的变量和命令,用于配置和控制项目的构建过程。以下是一些常用的变量和命令,以及它们的使用方式:1、TARGET:定义生成的可执行文件的名称。TARGET=MyApplication2、TEMPLATE:指定项目的类型,可以是"app"(应用程序)或"lib"(库)。TEMPLATE=app3......
  • 刘金玉QT学习笔记:7-简易用户信息管理界面实现_实现用户信息增改
    1.同第六课方式在widget里连接并创建数据库。 2.通过QSqlQuery使用sql语句的第二种方法:-在不同的函数中都要使用->做成全局变量 3.表格网格控件tableview控件显示数据库的内容为表格行-ui拖出控件-qtableview控件通过QSqlQueryModel来渲染数据过程:1widget.h引入#i......
  • 刘金玉QT学习笔记:6-sqlite简易入门+QT结合使用
    //第一篇,测试一下1.Sqlite-linux自带-轻量级-关系型数据库2.安装-进入官网后点击Downloads-下载下图的两个zip,解压后把里面的文件放到C盘下自创一个sqlite的文件夹3.通过命令行使用sqlite3.exe来使用数据库-配环境变量作用:不用进入路径位置就可以打开(sqlite)4.基本......
  • QT实战 之TableWidget控件
    QT实战之TableWidget控件指定列数setColumnCount(3)指定表头setHorizontalHeaderLabels(QStringList)指定行数setRowCount(5)设置每个单元格的内容setItem(int行数,int列数,*QTableWidgetItem内容)#include "tablewidget.h"#include "ui_tablewidget.h" TableWidge......