Qt音视频开发14-mpv读取和控制
一、前言
用mpv来读取文件的信息,以及设置当前播放进度,音量、静音等,和当时vlc封装的功能一样,只不过vlc是通过调用函数接口去处理,而mpv是通过读取和设置属性来处理,vlc支持定时器或者线程中函数方法去读取状态,也支持事件回调去拿到对应的状态改变,mpv当然也支持,而且还更方便,主要的工作量或者花费的时间在如何知道有哪些属性、分别是什么功能含义,这个在官方都列出来了(http://mpv.io/manual/master/#options、http://mpv.io/manual/master/#list-of-input-commands、http://mpv.io/manual/master/#properties),不过都是英文就是,大部分程序员应该是没有什么难度的,大不了鼠标右键翻译成中文即可,哈哈,相信不少人都这么干过,很多浏览器默认就支持鼠标右键菜单翻译的,实在是很方便的,本人在查阅很多英文文档的时候,用的也是蛮多的,包括Qt官方的文档和BUG报告页面,但是建议在搜索问题的时候还是建议尽量用英文的描述去搜索,这样才能搜索的更精确。
常用的一些属性:
- 视频原始宽度高度 width height
- 视频缩放后宽度高度 dwidth dheight
- 保存视频文件 stream-record 为空则表示停止录像
- 视频宽高比 video-aspect
- 暂停播放 pause yes表示暂停no表示继续
- 视频文件时长 duration
- 静音 mute yes表示静音no表示非静音
- 音量 volume int值0-100
- 获取播放进度 time-pos
- 设置播放进度 seek
- 当前音轨 aid
- 音轨数量 track-list/count
- 截图 screenshot-to-file
二、功能特点
- 多线程实时播放视频流+本地视频等。
- 支持windows+linux+mac。
- 多线程显示图像,不卡主界面。
- 自动重连网络摄像头。
- 可设置是否保存到文件以及文件名。
- 可直接拖曳文件到mpvwidget控件播放。
- 支持h265视频流+rtmp等常见视频流。
- 可暂停播放和继续播放。
- 支持存储单个视频文件和定时存储视频文件。
- 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
- 可设置画面拉伸填充或者等比例填充。
- 可对视频进行截图(原始图片)和截屏。
- 录像文件存储MP4文件。
- 支持qsv、dxva2、d3d11va等硬解码。
三、效果图

四、相关站点
- 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
- 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
- 个人主页:https://blog.csdn.net/feiyangqingyun
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
- 体验地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652
五、核心代码
void MpvThread::readMediaInfo()
{
if (mpvPlayer != NULL) {
QVariant width = getValue("width");
QVariant height = getValue("height");
videoWidth = width.toInt();
videoHeight = height.toInt();
qDebug() << TIMEMS << url << "videoWidth:" << videoWidth << "videoHeight:" << videoHeight;
}
}
void MpvThread::readPlayInfo()
{
//定义长度变量用于存储文件时长
uint length = getLength();
//定义变量存储声音大小,默认值1
int volume = getVolume();
//定义变量存储是否静音
bool mute = getMute();
//发送文件时长信号
emit fileLengthReceive(length);
//发送当前音量值信号
emit fileVolumeReceive(volume, mute);
//改变标志位启动读取播放进度
if (!callbackevent) {
isReadPosition = true;
}
}
void MpvThread::readPosition()
{
//获取播放进度位置
int position = getPosition();
//获取是否播放结束
bool isPlay = (position != 0);
if (position > 0 && !isRtsp) {
emit filePositionReceive(position, isPlay);
}
//本地文件播放结束
if (!isPlay && !isRtsp && suffix != "dshow") {
this->stop();
}
}
void MpvThread::setSize()
{
if (mpvPlayer != NULL) {
double width = playWidget->width();
double height = playWidget->height();
setValue("video-aspect", width / height);
}
}
bool MpvThread::getIsPlaying()
{
//在视频流模式下,不是暂停状态,当前的位置和上一次的位置一致则表示断了
//进度为0表示没有播放成功也需要重新加载
bool isPlay = this->isRunning();
if (isPlay && isRtsp && !getValue("pause").toBool()) {
int position = getPosition();
if (position == 0 || this->position == position) {
isPlay = false;
}
this->position = position;
}
return isPlay;
}
uint MpvThread::getLength()
{
uint length = 0;
if (mpvPlayer != NULL) {
QVariant value = getValue("duration");
length = value.toDouble() * 1000;
}
return length;
}
uint MpvThread::getPosition()
{
uint positon = 0;
if (mpvPlayer != NULL) {
QVariant value = getValue("time-pos");
positon = value.toDouble() * 1000;
}
return positon;
}
void MpvThread::setPosition(int position)
{
if (mpvPlayer != NULL && !isRtsp) {
command(QVariantList() << "seek" << position / 1000 << "absolute");
}
}
bool MpvThread::getMute()
{
bool ok = false;
if (mpvPlayer != NULL) {
QVariant value = getValue("mute");
ok = !value.toBool();
}
return ok;
}
void MpvThread::setMute(bool mute)
{
if (mpvPlayer != NULL) {
setValue("mute", mute ? "yes" : "no");
}
}
int MpvThread::getVolume()
{
int volume = 0;
if (mpvPlayer != NULL) {
QVariant value = getValue("volume");
volume = value.toInt();
}
return volume;
}
void MpvThread::setVolume(int volume)
{
if (mpvPlayer != NULL) {
setValue("volume", volume);
}
}
int MpvThread::getTrack()
{
int track = 0;
if (mpvPlayer != NULL) {
QVariant value = getValue("aid");
track = value.toInt();
}
return track;
}
int MpvThread::getTrackCount()
{
int trackCount = 0;
if (mpvPlayer != NULL) {
QVariant value = getValue("track-list/count");
trackCount = value.toInt();
}
return trackCount;
}
void MpvThread::setTrack(int track)
{
if (mpvPlayer != NULL) {
setValue("aid", track);
}
}
Qt音视频开发14-mpv读取和控制的更多相关文章
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- 【秒懂音视频开发】02_Windows开发环境搭建
音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
- Android开发 音视频开发需要了解的专业术语知识
前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...
- 音视频开发-FFmpeg
音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...
- Python音视频开发:消除抖音短视频Logo的图形化工具实现
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...
- Python音视频开发:消除抖音短视频Logo和去电视台标
☞ ░ 前往老猿Python博文目录 ░ 一.引言 对于带Logo(如抖音Logo.电视台标)的视频,有三种方案进行Logo消除: 直接将对应区域用对应图像替换: 直接将对应区域模糊化: 通过变换将要 ...
- moviepy音视频开发:使用credits1给视频加片头片尾字幕
☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:视频基类VideoClip子类DataVideoClip.UpdatedVideoClip.ImageClip. ...
- moviepy音视频开发:音频剪辑基类AudioClip
☞ ░ 前往老猿Python博文目录 ░ 一.背景知识介绍 1.1.声音三要素: 音调:人耳对声音高低的感觉称为音调(也叫音频).音调主要与声波的频率有关.声波的频率高,则音调也高. 音量:也就是响度 ...
随机推荐
- TiDB集群安装维护
TIDB安装操作文档-https://docs.pingcap.com/zh/tidb/stable/production-deployment-using-tiup 1.环境准备(每台) 1-查看系 ...
- 某物联网数智化园区行业基于 KubeSphere 的云原生实践
公司简介 作为物联网 + 数智化园区一体化解决方案提供商,我们致力于为大中型园区.停车场提供软硬件平台,帮助园区运营者实现数字化.智能化运营. 在使用 K8s 之前我们使用传统的方式部署上线,使用 s ...
- appium-命令行启动appium-server(windows)
首先找到build\lib\main.js所在位置,我用的工具是everything(推荐一波),比windows自带的搜索强太多 执行命令:node C:\Users\Acer\AppData\Ro ...
- 在嵌入式设备中实现webrtc的第三种方式②
先贴上效果图以及操作路径. 操作路径为:启动信令服务器,配置浏览器关闭mDNS,双端登录,浏览器端邀请.最终连接成功建立,我们通过datachannel成功通信 (关闭mDNS是因为谷歌浏览器隐藏了局 ...
- NOIP2023模拟2联测23 T2 害怕
NOIP2023模拟2联测23 T2 害怕 好像写了一种出题人意料之外的算法. 思路 在生成树上加入白边,白边和若干条蓝色边形成环,环上的蓝色边必须要分配比该白色边更小的边权(最小生成树). 给每一条 ...
- 曲线救国--访问dockerhub仓库
前言 由于dockerhub也被墙了,导致基础镜像没法拉取.后面解封了,又被墙了... 在这次被墙之前,访问国外的速度也是堪忧,甚至访问不了k8s的镜像,基于此,分享一下笔者经验 使用Daocloud ...
- AtCoder Beginner Contest 295
Three Days Ago 我们定义一个只由数字构成的字符串中的字符能够被重排成相同的两份,我们称这个字符串是个好字符串,比如12341234 现在给定一个字符串\(S\),找出所有的\([l,r] ...
- JavaScript 页面缓存
1.前言 由来:默认环境中,当浏览器重复访问一个资源时,为节省资源与性能,浏览器将其缓存,后续的请求不再从服务器下载该资源,而是直接从本地缓存中读取,默认时没有强制缓存的 副作用:当服务器资源更新时, ...
- 一款基于 .NET + Blazor 开发的智能访客管理系统
前言 在小区.企业.学校等场所,访客管理作为日常运营中不可或缺的一环,其重要性日益凸显.传统的访客管理方式往往依赖于人工登记.纸质记录,不仅效率低下,还存在信息易丢失.难以追溯等问题.今天大姚给大家分 ...
- StarBlog博客Vue前端开发笔记:(2)页面路由
前言 Vue.js 使用虚拟 DOM 处理单页面,然后使用 Webpack 打包.通过上一篇文章的例子,读者也许已经发现,无论语法和写法如何不同,Vue.js 程序打包后都是一个单一的 HTML 文件 ...