Qt/C++实现帧同步播放器/硬解码GPU绘制/超低资源占用/支持8K16K/支持win/linux/mac/嵌入式/国产OS等

一、前言

首先泼一盆冷水,在不同的电脑上实现完完全全的帧同步理论上是不可能的,市面上所有号称帧同步的播放器,同一台电脑不同拼接视频可以通过合并成一张图片来绘制实现完完全全的帧同步,不同电脑,受限于网络的延迟,命令交互的时间占用,不同硬件之间的主频偏差等,肯定会有些许的误差,只要误差控制在1帧以内,人的肉眼是完全看不出来的,比如误差5ms,看不出来的。这个和零延迟的推流软件道理一样,不可能零延迟的,只能够做到肉眼分不清的延迟,就已经可以了。

搞帧同步播放核心就两点,第一点保证帧序号一致,第二点保证刷新的时间一致。两者缺一不可,否则无法实现真正的帧同步。序号一致这个搞音视频开发的都能做到,可以先缓存也好,暂停也好,程序底层肯定是知道当前要播放的是第几帧。保证刷新时间一致这个也非常关键,哪怕是在同一台电脑,由于分时多任务操作系统是通过中断来并发执行指令的,指令的传递和最终的绘制都有时间偏差,尤其是在资源占用很多的时候,所以一个技巧就是,等待,等到所有视频帧全部解码完整就差绘制的时候,然后让多个界面同时绘制,这样就能将误差控制在极低极低范围,基本上控制在1帧以内比如5ms。在现在的多任务操作系统中,完全一致肯定是不可能的,一般可能会有1-2个中断的时间差,可能有5-10ms的差,不过没关系,一般25fps也要40ms才有一帧,哪怕是60fps的也要16.7ms一帧,这个误差几乎不影响。

二、效果图

三、相关地址

  1. 国内站点:https://gitee.com/feiyangqingyun
  2. 国际站点:https://github.com/feiyangqingyun
  3. 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
  4. 文件地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_sync。

四、功能特点

  1. 实时帧同步,本地无缝拼接多个视频。
  2. 支持网络同步,可选主控端和被控端,主控端将本地播放的进度实时同步到被控端。
  3. 网络同步支持组播、广播、单播三种模式,默认组播,既可以跨网段,也可以避免广播数据风暴。
  4. 默认开启自动同步,也可以手动同步和复位同步,手动同步是立即执行一次同步,将第一个视频的进度同步到其他视频文件,复位同步是将所有视频播放进度切换到最开始0的位置。
  5. 支持各种视音频文件,包括但不限于mp4/mov/mkv/rmvb/avi等格式。
  6. 硬解码和GPU绘制,最大化利用硬件资源,支持qsv/cuda/dxva2/d3d11va/vaapi等硬解码。
  7. 极低的CPU占用,8K30fps只占不到1%的CPU,解码和绘制全部交给GPU。
  8. 提供示例按照行列生成多个视频播放窗口,每个窗口可以选择不同的视频文件,在手动同步模式下,可以切换任意一个视频播放进度,会将所有的视频按照这个进度同步。
  9. 自动循环播放视频文件,无缝切换循环播放,看起来非常丝滑。
  10. 支持Qt4/Qt5/Qt6所有版本,支持各种操作系统包括国产OS和嵌入式OS。

五、相关代码

#include "synclocal.h"
#include "qthelper.h"
#include "frmplay.h"SINGLETON_IMPL(SyncLocal)
QDateTime SyncLocal::SyncTime = QDateTime::currentDateTime().addDays(-1);
SyncLocal::SyncLocal(QObject *parent) : QThread(parent)
{isStop = false;this->reset();syncInterval = 5;syncOffset = 15;syncSleep = 500;updateInterval = 10;
}SyncLocal::~SyncLocal()
{this->stop();
}void SyncLocal::run()
{while (!isStop) {this->checkPosition();this->checkSync();this->checkPause();this->updateWidget();count++;msleep(updateInterval);//qDebug() << TIMEMS << "111" << updateInterval << count;}isStop = false;this->reset();
}void SyncLocal::checkPosition()
{//同步间隔0表示不启用/至少要2个窗体才需要同步int size = frmPlay::widgets.size();if (size < 2 || isSync || isPasue) {count = 0;return;}//永远同步到到第一个窗体/处于非播放状态或者暂停状态不用继续frmPlay *widget = frmPlay::widgets.first();if (!widget->isPlaying() || widget->isPaused()) {return;}//优先执行手动同步指令/-1则同步到第一个窗体/>=0则同步到对应位置if (syncPosition >= -1) {position = (syncPosition == -1 ? widget->position() : syncPosition);count = 0;isSync = true;qDebug() << TIMEMS << "hand" << position;return;}//同步间隔0表示不启用if (syncInterval == 0) {count = 0;return;}//计算同步间隔需要循环多少次int maxCount = syncInterval * 1000 / updateInterval;//到了需要同步的时候执行同步if (count < maxCount) {return;}count = 0;position = widget->position();//刚开始或者快结束先不同步if (position < 1000 || qAbs(widget->duration() - position) < 1000) {return;}for (int i = 1; i < size; ++i) {offset = position - frmPlay::widgets.at(i)->position();qDebug() << TIMEMS << "posi" << position << "\t" << offset;if (qAbs(offset) >= syncOffset) {isSync = true;break;}}
}void SyncLocal::checkSync()
{//同步标志位为真则先同步if (isSync) {count = 0;isSync = false;isPasue = true;SyncTime = QDateTime::currentDateTime();qDebug() << TIMEMS << "seek" << position;//先暂停再执行设置进度foreach (frmPlay *widget, frmPlay::widgets) {widget->pause();widget->seek(position);}}
}void SyncLocal::checkPause()
{//暂停阶段说明刚才执行过同步/等待一段时间重新播放if (isPasue) {qint64 time = SyncTime.msecsTo(QDateTime::currentDateTime());if (time >= syncSleep) {foreach (frmPlay *widget, frmPlay::widgets) {widget->next();}count = 0;isPasue = false;syncPosition = -2;emit receiveSync(offset);qDebug() << TIMEMS << "play" << position;}}
}void SyncLocal::updateWidget()
{//刷新界面用来触发绘制foreach (frmPlay *widget, frmPlay::widgets) {widget->updateVideo();}
}void SyncLocal::setSyncInterval(int syncInterval)
{this->reset();this->syncInterval = syncInterval;
}void SyncLocal::setSyncOffset(int syncOffset)
{this->syncOffset = syncOffset;
}void SyncLocal::setSyncSleep(int syncSleep)
{this->syncSleep = syncSleep;
}void SyncLocal::setUpdateInterval(int updateInterval)
{this->updateInterval = updateInterval;
}void SyncLocal::stop()
{if (this->isRunning()) {this->isStop = true;this->wait();}
}void SyncLocal::reset()
{this->count = 0;this->isSync = false;this->isPasue = false;this->syncPosition = -2;
}//-1则同步到第一个窗体/>=0则同步到对应位置
void SyncLocal::sync(qint64 position)
{//至少要两个窗体才能同步/处于暂停阶段说明上一个同步还没执行完成if (frmPlay::widgets.size() >= 2 && !isPasue && syncPosition == -2) {this->syncPosition = position;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845360.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EyeSoothe:用科技守护您的眼睛!

眼睛是心灵的窗口,而 EyeSoothe 则是您保护眼睛健康的智能助手。这款全新的护眼应用结合了人工智能和深度分析技术,为您提供全方位的视力管理服务,带来舒适与便利。 https://apps.apple.com/cn/app/eyesoothe/ 为什么选择 EyeSoothe? • AI智能试戴眼镜:借助AI虚拟试戴功能…

ai大模型流式输出------基于SSE协议的长连接实现

传统的http1.0请求开发,已经满足了我们日常的web开发。一般请求就像下图这样子,客服端发起一个请求(触发),服务端做出一个响应(动作): 有时会有诸如实时刷新,实时显示的场景,我们往往是客户端定时发起请求,不断的尝试获取最新的数据。但是每次请求都会创建并释放一个…

子卡设计原理图:232-基于FMC的2收2发TLK2711子卡

基于FMC的2收2发TLK2711子卡 一、板卡概述TLK2711 是千兆位收发器,专用于超高速双向点对点数据传输系统。TLK2711与时钟芯片SI5338相结合支持1.6Gbps至2.5Gbps的有效串行接口速度,可提供高达 2Gbps的数据带宽。板卡包含2路TLK2711,实现2收2发 。二、技术规格 ● 电源供电:F…

Python 存储验证码至redis

存储时考虑原子性 import redis# 实例化redis对象r = redis.Redis(host=localhost, port=6379, db=5,decode_responses=True)# 随机码的存储 def save_code(email,lifetime,code):# 原子操作,确保原子性 都执行或都不执行# 原子性保存验证码return r.setex(email,lifetime,cod…

【终端】终端配置、Vim使用相关

终端设置 MobaXterm主题 GithubVim 设置相关设置显示行号/etc/vimrc 是系统范围的初始化配置 ~/.vimrc 个人的vim初始化配置如果没有个人的vim初始化配置:touch ~/.vimrc vim ~/.vimrc设置好保存退出 wq使用相关跳转跳转指定行 :100跳转到100行 跳转到最开头 gg 跳转到最末…

idea的如何git代码进行合并

案例,将dev-wsg 的部分代码提交,合并到develop中1、先使用命令,将分支切换到develop分支 git checkout develop2、在idea 底部,选中这个标签页 3、选中要合并的提交,选择优选。这样本地的代码,会合并到本地develop分支中 4、优选后,如果分支右侧显示还要推送,则要进行…

11.30学习日记

11.30学习日记 oj 跑项目报错如下查问题,改成java8这个路径也要改掉这里用的是木马程序测试路径 改成我们正常测试的main.java就行运行成功

携程酒店库存查询接口(接单被骗直接放出接口)

本来是接单的,做了一个查询库存自动到他们系统里下库存的单子,做好部署好,老板可能也有点技术,拿了跑路了,那就放出来,给大家用 接口请求格式:https://down.ychengsnsm.com/jd/api.php?id=48565681&checkinDate=2024-12-30 测试图:id就是酒店id,随便到携程到个酒…

jQuery和CSS3超酷3D翻转式模态对话框插件

jquery-awesomodals是一款JQUERY和CSS3超酷3D翻转式模态对话框插件。该对话框特效通过jquery和CSS3 transitions和transforms来在对话框打开时制作3D翻转的效果,效果非常的酷。在线演示 下载安装 可以通过bower来安装jquery-awesomodals插件。$ bower install jquery-awesomo…

软件工程课堂测试九

软件需求与分析课堂测试九—结构化建模分析II(100分) (45分钟)1、 需求描述: 请设计一个仓储管理系统原型系统,该系统支持多个仓库的设立。统一 设立物资台账,物资台账需包含物资编码、物资名称、规格、材质、供应商、 品牌、物资分类,用户可以自定义物资的物资分类。…

Zabbix7 乱码处理

Zabbix7 乱码处理 Zabbix安装好后,查看图形时下面的文字往往显示不出来从windows主机 C:\Windows\Fonts拷贝字体文件双击打开,拷贝文件到桌面上传到 Zabbix主机以下目录(可以使用lrzsz 上传,安装方式 dnf install lrzsz -y) /usr/share/zabbix/assets/fonts 修改配置文件vim…