一、前言

一直都想搞个安卓版本的视频监控程序,很早以前弄过一个,采用的是早期的ffmpeg2的lib文件,对于现在众多的网络流媒体格式,支持有限,而且新的Qt编写安卓程序,结构上也变动了,新的安卓系统权限要求也和以前处理不一样了,现在需要动态授权,以前是直接配置文件写好需要哪些权限就行,所以近期特意全部重写了一遍安卓版本的视频监控程序,内核还是采用的ffmpeg,换成了最新的ffmpeg4版本,在ubuntu系统上用安卓编译器编译了对应的lib文件,然后放到win上编写Qt+安卓程序。

为了统一管理一个版本的ffmpeg视频监控内核程序,直接在现有的程序上修改,增加了动态申请权限的代码,同时对应的进度条和复选框等指示器放大,方便选中,通道画面限定默认4个,可以自行增加画面数量,一开始测试保存截图和视频文件的时候,发现死活不成功,后面动态权限申请成功以后,把把成功,这里搞了很久,原来对不一样的安卓系统处理要求不一样。新时代新技术层出不穷,迭代真是非常的快,想要保持活力看来还得不断的学习及了解新技术新知识。一个有前途的程序员每天60%的时间要拿出来学习研究,40%用来应付工作,这样每两年工资可翻一倍,而且最要命的是程序员也是要有一些天赋的,并非所有人都适合,大部分程序员把时间都扔在了业务逻辑之中,最后被淘汰!这也是35岁中年危机的主要原因。事实上有实力的程序员越老越值钱,扯远了!

二、功能特点

  1. 多线程实时播放视频流+本地视频+USB摄像头等。
  2. 支持windows+linux+mac,支持ffmpeg3和ffmpeg4,支持32位和64位。
  3. 多线程显示图像,不卡主界面。
  4. 自动重连网络摄像头。
  5. 可设置边框大小即偏移量和边框颜色。
  6. 可设置是否绘制OSD标签即标签文本或图片和标签位置。
  7. 可设置两种OSD位置和风格。
  8. 可设置是否保存到文件以及文件名。
  9. 可直接拖曳文件到ffmpegwidget控件播放。
  10. 支持h265视频流+rtmp等常见视频流。
  11. 可暂停播放和继续播放。
  12. 支持存储单个视频文件和定时存储视频文件。
  13. 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
  14. 可设置画面拉伸填充或者等比例填充。
  15. 可设置解码是速度优先、质量优先、均衡处理。
  16. 可对视频进行截图(原始图片)和截屏。
  17. 录像文件存储支持裸流和MP4文件。
  18. 音视频完美同步,采用外部时钟同步策略。
  19. 支持seek定位播放位置。
  20. 支持qsv、dxva2、d3d11va等硬解码。
  21. 支持opengl绘制视频数据,极低CPU占用。
  22. 支持安卓和嵌入式linux,交叉编译即可。

三、效果图





四、相关站点

  1. 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
  2. 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
  3. 个人主页:https://blog.csdn.net/feiyangqingyun
  4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
  5. 体验地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652

五、核心代码

#include "head.h"
#include "frmtab.h" //动态设置权限
bool checkPermission(const QString &permission)
{
#ifdef Q_OS_ANDROID
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QtAndroid::PermissionResult result = QtAndroid::checkPermission(permission);
if (result == QtAndroid::PermissionResult::Denied) {
QtAndroid::requestPermissionsSync(QStringList() << permission);
result = QtAndroid::checkPermission(permission);
if (result == QtAndroid::PermissionResult::Denied) {
return false;
}
}
#endif
#endif
return true;
} void initStyle()
{
//复选框单选框滑块等指示器大小
QStringList list;
int rbtnWidth = 20;
int ckWidth = 18;
list.append(QString("QRadioButton::indicator{width:%1px;height:%1px;}").arg(rbtnWidth));
list.append(QString("QCheckBox::indicator,QGroupBox::indicator,QTreeWidget::indicator,QListWidget::indicator{width:%1px;height:%1px;}").arg(ckWidth)); QString normalColor = "#E8EDF2";
QString grooveColor = "#1ABC9C";
QString handleColor = "#1ABC9C";
int sliderHeight = 12;
int sliderRadius = sliderHeight / 2;
int handleWidth = (sliderHeight * 3) / 2 + (sliderHeight / 5);
int handleRadius = handleWidth / 2;
int handleOffset = handleRadius / 2; list.append(QString("QSlider::horizontal{min-height:%1px;}").arg(sliderHeight * 2));
list.append(QString("QSlider::groove:horizontal{background:%1;height:%2px;border-radius:%3px;}")
.arg(normalColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::add-page:horizontal{background:%1;height:%2px;border-radius:%3px;}")
.arg(normalColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::sub-page:horizontal{background:%1;height:%2px;border-radius:%3px;}")
.arg(grooveColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::handle:horizontal{width:%2px;margin-top:-%3px;margin-bottom:-%3px;border-radius:%4px;"
"background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #FFFFFF,stop:0.8 %1);}")
.arg(handleColor).arg(handleWidth).arg(handleOffset).arg(handleRadius)); //偏移一个像素
handleWidth = handleWidth + 1;
list.append(QString("QSlider::vertical{min-width:%1px;}").arg(sliderHeight * 2));
list.append(QString("QSlider::groove:vertical{background:%1;width:%2px;border-radius:%3px;}")
.arg(normalColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::add-page:vertical{background:%1;width:%2px;border-radius:%3px;}")
.arg(grooveColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::sub-page:vertical{background:%1;width:%2px;border-radius:%3px;}")
.arg(normalColor).arg(sliderHeight).arg(sliderRadius));
list.append(QString("QSlider::handle:vertical{height:%2px;margin-left:-%3px;margin-right:-%3px;border-radius:%4px;"
"background:qradialgradient(spread:pad,cx:0.5,cy:0.5,radius:0.5,fx:0.5,fy:0.5,stop:0.6 #FFFFFF,stop:0.8 %1);}")
.arg(handleColor).arg(handleWidth).arg(handleOffset).arg(handleRadius)); qApp->setStyleSheet(list.join(""));
} int main(int argc, char *argv[])
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
#if (QT_VERSION > QT_VERSION_CHECK(5,4,0))
//设置opengl模式 AA_UseDesktopOpenGL AA_UseSoftwareOpenGL AA_UseOpenGLES
//QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
QApplication a(argc, argv); App::setFont();
App::setCode();
App::ConfigFile = AppPath + "/video_ffmpeg.ini";
App::readConfig(); frmTab w;
#ifdef Q_OS_ANDROID
//请求权限
checkPermission("android.permission.READ_EXTERNAL_STORAGE");
checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); QString strDir = AppPath + "/snap";
QDir dir(strDir);
if (!dir.exists()) {
dir.mkpath(strDir);
} initStyle();
w.showMaximized();
#else
w.resize(1100, 700);
w.setWindowTitle(QString("qt+ffmpeg 示例 %1 %2").arg(App::Version).arg(App::TitleFlag));
w.show();
App::setFormInCenter(&w);
#endif return a.exec();
}

Qt音视频开发33-ffmpeg安卓版的更多相关文章

  1. 【秒懂音视频开发】02_Windows开发环境搭建

    音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...

  2. 音视频开发-FFmpeg

    音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...

  3. WebRTC 音视频开发

    WebRTC 音视频开发 webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...

  4. 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)

    随笔分类 - webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...

  5. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  6. Android 音视频开发入门指南

    Android 音视频从入门到提高 —— 任务列表 http://blog.51cto.com/ticktick/1956269(以这个学习为基础往下面去学习) Android 音视频开发学习思路-- ...

  7. Python音视频开发:消除抖音短视频Logo的图形化工具实现

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...

  8. Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...

  9. moviepy音视频开发:使用credits1给视频加片头片尾字幕

    ☞ ░ 前往老猿Python博文目录 ░ 一.概述 在<moviepy音视频剪辑:视频基类VideoClip子类DataVideoClip.UpdatedVideoClip.ImageClip. ...

  10. moviepy音视频开发:音频剪辑基类AudioClip

    ☞ ░ 前往老猿Python博文目录 ░ 一.背景知识介绍 1.1.声音三要素: 音调:人耳对声音高低的感觉称为音调(也叫音频).音调主要与声波的频率有关.声波的频率高,则音调也高. 音量:也就是响度 ...

随机推荐

  1. 安装完Oracle数据库后需要调整的参数

    关闭审计 alter system set audit_trail = none scope=spfile; 180天密码过期 alter profile default limit PASSWORD ...

  2. 神经网络之卷积篇:详解残差网络(ResNets)(Residual Networks (ResNets))

    详解残差网络 ResNets是由残差块(Residual block)构建的,首先解释一下什么是残差块. 这是一个两层神经网络,在\(L\)层进行激活,得到\(a^{\left\lbrack l + ...

  3. 关系图谱后端不给指向性字段使用children

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  4. KubeSphere 社区双周报|Fluent Bit 升级到 v2.2.2|2024.01.18-02.01

    KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...

  5. while循环和do循环、缓冲区、一维数组

    缓冲区 输入缓冲区 从键盘得到数据的时候用户输入的数据首先进入输入缓冲区,然后程序从输入缓冲区里获得数字,先进入输入缓冲区的数据必须先处理(类似排队),如果先进入输入缓冲区的数据无法处理,程序就得不到 ...

  6. Ubuntu自动连接到虚拟专用网络

    在我们继续之前,我们所做的一个重要假设是,您已经拥有了虚拟专用网络客户端配置文件. 您可以通过以下链接在我们的上一指南中看到一个示例 Open虚拟专用网络 客户端配置文件: 在 CentOS 8/乌本 ...

  7. 带你玩转nginx负载均衡

    nginx跨多个应用程序实例的负载平衡是一种用于优化资源利用率,最大化吞吐量,减少延迟和确保容错配置的常用技术. 环境介绍 配置nginx负载均衡器因会用到多台服务器来进行,所以下面我会用到docke ...

  8. 认识JVM

    类加载器 运行时数据区 执行引擎 执行引擎的任务就是将字节码指令解释/编译为对应平台上的本地机器指令 JVM架构图

  9. ArgoWorkflow教程(七)---高效的步骤间文件共享策略

    之前我们分析了使用 artifact 实现步骤间文件共享,今天分享一下如何使用 PVC 实现高效的步骤间文件共享. 1. 概述 之前在 artifact 篇我们演示了如何使用 artifact 实现步 ...

  10. java中bimface 在线申请token。模型视角 模型批注处理

    在线申请token 1.首先引入包 <dependency> <groupId>com.bimface</groupId> <artifactId>bi ...