Qt/C++音视频开发55-加密保存到文件并解密播放

news2024/11/17 11:50:21

一、前言

为了保证视频文件的安全性,有时候需要对保存的视频文件加密,然后播放的时候解密出来再播放,只有加密解密的秘钥一致时才能正常播放,用ffmpeg做视频文件的加密保存和解密播放比较简单,基于ffmpeg强大的字典参数设计,在avformat_write_header写入头部数据的时候,可以通过万能的av_dict_set来给options设置encryption_scheme/encryption_key/encryption_kid三键值,这样保存后的文件是加密过的,第三方播放器都无法正常播放,需要用ffmpeg打开并设置一样的秘钥才能解密播放,打开这边也是通过av_dict_set来给options设置decryption_key键值,在调用avformat_open_input的时候传入options即可。这种加密解密的应用场景一般在对视频文件要求安全性很高的地方,相当于需要定制播放器才能正常播放,做的好一点的话,还可以自定义格式,文件格式关联到定制的播放器,如果默认的MP4文件格式,可能用户不自觉的还会去双击播放,打不开就会很纳闷,所以针对这种加密过的视频文件一般定义一个自定义的格式保存比较好,拓展名仅仅是个名字,和里面的内容无关,内容都是二进制数据。

查阅资料得知,加密和未加密的文件,就是在头部数据中stbl下新增加了3个box。

  • senc:sample specific encryption data,特定加密数据样本。
  • saio:sample auxiliary information offsets,样本辅助信息偏移量。
  • saiz:sample auxiliary information sizes,样本辅助信息大小。

二、效果图

在这里插入图片描述

三、体验地址

  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_demo。

四、功能特点

1. 基础功能

  1. 支持各种音频视频文件格式,比如mp3、wav、mp4、asf、rm、rmvb、mkv等。
  2. 支持本地摄像头设备,可指定分辨率、帧率。
  3. 支持各种视频流格式,比如rtp、rtsp、rtmp、http等。
  4. 本地音视频文件和网络音视频文件,自动识别文件长度、播放进度、音量大小、静音状态等。
  5. 文件可以指定播放位置、调节音量大小、设置静音状态等。
  6. 支持倍速播放文件,可选0.5倍、1.0倍、2.5倍、5.0倍等速度,相当于慢放和快放。
  7. 支持开始播放、停止播放、暂停播放、继续播放。
  8. 支持抓拍截图,可指定文件路径,可选抓拍完成是否自动显示预览。
  9. 支持录像存储,手动开始录像、停止录像,部分内核支持暂停录像后继续录像,跳过不需要录像的部分。
  10. 支持无感知切换循环播放、自动重连等机制。
  11. 提供播放成功、播放完成、收到解码图片、收到抓拍图片、视频尺寸变化、录像状态变化等信号。
  12. 多线程处理,一个解码一个线程,不卡主界面。

2. 特色功能

  1. 同时支持多种解码内核,包括qmedia内核(Qt4/Qt5/Qt6)、ffmpeg内核(ffmpeg2/ffmpeg3/ffmpeg4/ffmpeg5)、vlc内核(vlc2/vlc3)、mpv内核(mpv1/mp2)、海康sdk、easyplayer内核等。
  2. 非常完善的多重基类设计,新增一种解码内核只需要实现极少的代码量,就可以应用整套机制。
  3. 同时支持多种画面显示策略,自动调整(原始分辨率小于显示控件尺寸则按照原始分辨率大小显示,否则等比缩放)、等比缩放(永远等比缩放)、拉伸填充(永远拉伸填充)。所有内核和所有视频显示模式下都支持三种画面显示策略。
  4. 同时支持多种视频显示模式,句柄模式(传入控件句柄交给对方绘制控制)、绘制模式(回调拿到数据后转成QImage用QPainter绘制)、GPU模式(回调拿到数据后转成yuv用QOpenglWidget绘制)。
  5. 支持多种硬件加速类型,ffmpeg可选dxva2、d3d11va等,mpv可选auto、dxva2、d3d11va,vlc可选any、dxva2、d3d11va。不同的系统环境有不同的类型选择,比如linux系统有vaapi、vdpau,macos系统有videotoolbox。
  6. 解码线程和显示窗体分离,可指定任意解码内核挂载到任意显示窗体,动态切换。
  7. 支持共享解码线程,默认开启并且自动处理,当识别到相同的视频地址,共享一个解码线程,在网络视频环境中可以大大节约网络流量以及对方设备的推流压力。国内顶尖视频厂商均采用此策略。这样只要拉一路视频流就可以共享到几十个几百个通道展示。
  8. 自动识别视频旋转角度并绘制,比如手机上拍摄的视频一般是旋转了90度的,播放的时候要自动旋转处理,不然默认是倒着的。
  9. 自动识别视频流播放过程中分辨率的变化,在视频控件上自动调整尺寸。比如摄像机可以在使用过程中动态配置分辨率,当分辨率改动后对应视频控件也要做出同步反应。
  10. 音视频文件无感知自动切换循环播放,不会出现切换期间黑屏等肉眼可见的切换痕迹。
  11. 视频控件同时支持任意解码内核、任意画面显示策略、任意视频显示模式。
  12. 视频控件悬浮条同时支持句柄、绘制、GPU三种模式,非绝对坐标移来移去。
  13. 本地摄像头设备支持指定设备名称、分辨率、帧率进行播放。
  14. 录像文件同时支持打开的视频文件、本地摄像头、网络视频流等。
  15. 瞬间响应打开和关闭,无论是打开不存在的视频或者网络流,探测设备是否存在,读取中的超时等待,收到关闭指令立即中断之前的操作并响应。
  16. 支持打开各种图片文件,支持本地音视频文件拖曳播放。
  17. 视频控件悬浮条自带开始和停止录像切换、声音静音切换、抓拍截图、关闭视频等功能。
  18. 音频组件支持声音波形值数据解析,可以根据该值绘制波形曲线和柱状声音条,默认提供了声音振幅信号。
  19. 标签和图形信息支持三种绘制方式,绘制到遮罩层、绘制到图片、源头绘制(对应信息可以存储到文件)。
  20. 各组件中极其详细的打印信息提示,尤其是报错信息提示,封装的统一打印格式。针对现场复杂的设备环境测试极其方便有用,相当于精确定位到具体哪个通道哪个步骤出错。
  21. 代码框架和结构优化到最优,性能强悍,持续迭代更新升级。
  22. 源码支持Qt4、Qt5、Qt6,兼容所有版本。

3. 视频控件

  1. 可动态添加任意多个osd标签信息,标签信息包括名字、是否可见、字号大小、文本文字、文本颜色、标签图片、标签坐标、标签格式(文本、日期、时间、日期时间、图片)、标签位置(左上角、左下角、右上角、右下角、居中、自定义坐标)。
  2. 可动态添加任意多个图形信息,这个非常有用,比如人工智能算法解析后的图形区域信息直接发给视频控件即可。图形信息支持任意形状,直接绘制在原始图片上,采用绝对坐标。
  3. 图形信息包括名字、边框大小、边框颜色、背景颜色、矩形区域、路径集合、点坐标集合等。
  4. 每个图形信息都可指定三种区域中的一种或者多种,指定了的都会绘制。
  5. 内置悬浮条控件,悬浮条位置支持顶部、底部、左侧、右侧。
  6. 悬浮条控件参数包括边距、间距、背景透明度、背景颜色、文本颜色、按下颜色、位置、按钮图标代码集合、按钮名称标识集合、按钮提示信息集合。
  7. 悬浮条控件一排工具按钮可自定义,通过结构体参数设置,图标可选图形字体还是自定义图片。
  8. 悬浮条按钮内部实现了录像切换、抓拍截图、静音切换、关闭视频等功能,也可以自行在源码中增加自己对应的功能。
  9. 悬浮条按钮对应实现了功能的按钮,有对应图标切换处理,比如录像按钮按下后会切换到正在录像中的图标,声音按钮切换后变成静音图标,再次切换还原。
  10. 悬浮条按钮单击后都用名称唯一标识作为信号发出,可以自行关联响应处理。
  11. 悬浮条空白区域可以显示提示信息,默认显示当前视频分辨率大小,可以增加帧率、码流大小等信息。
  12. 视频控件参数包括边框大小、边框颜色、焦点颜色、背景颜色(默认透明)、文字颜色(默认全局文字颜色)、填充颜色(视频外的空白处填充黑色)、背景文字、背景图片(如果设置了图片优先取图片)、是否拷贝图片、缩放显示模式(自动调整、等比缩放、拉伸填充)、视频显示模式(句柄、绘制、GPU)、启用悬浮条、悬浮条尺寸(横向为高度、纵向为宽度)、悬浮条位置(顶部、底部、左侧、右侧)。

五、相关代码

bool FFmpegSave::initStream()
{
    AVDictionary *options = NULL;
    QByteArray fileData = fileName.toUtf8();
    const char *url = fileData.data();

    //既可以是保存到文件也可以是推流(对应格式要区分)
    const char *format = "mp4";
    if (videoIndexIn < 0 && audioCodecName == "mp3") {
        format = "mp3";
    }
    if (fileName.startsWith("rtmp://")) {
        format = "flv";
    } else if (fileName.startsWith("rtsp://")) {
        format = "rtsp";
        av_dict_set(&options, "stimeout", "3000000", 0);
        av_dict_set(&options, "rtsp_transport", "tcp", 0);
    } else if (fileName.startsWith("udp://")) {
        format = "mpegts";
    }

    //如果存在秘钥则启用加密
    QByteArray cryptoKey = this->property("cryptoKey").toByteArray();
    if (!cryptoKey.isEmpty()) {
        av_dict_set(&options, "encryption_scheme", "cenc-aes-ctr", 0);
        av_dict_set(&options, "encryption_key", cryptoKey.constData(), 0);
        av_dict_set(&options, "encryption_kid", cryptoKey.constData(), 0);
    }

    //开辟一个格式上下文用来处理视频流输出(末尾url不填则rtsp推流失败)
    int result = avformat_alloc_output_context2(&formatCtx, NULL, format, url);
    if (result < 0) {
        debug(result, "创建格式", "");
        return false;
    }

    //创建输出视频流
    if (!this->initVideoStream()) {
        goto end;
    }

    //创建输出音频流
    if (!this->initAudioStream()) {
        goto end;
    }

    //打开输出文件
    if (!(formatCtx->oformat->flags & AVFMT_NOFILE)) {
        result = avio_open(&formatCtx->pb, url, AVIO_FLAG_WRITE);
        if (result < 0) {
            debug(result, "打开输出", "");
            goto end;
        }
    }

    //写入文件开始符
    result = avformat_write_header(formatCtx, &options);
    if (result < 0) {
        debug(result, "写文件头", "");
        goto end;
    }

    return true;

end:
    //关闭释放并清理文件
    this->close();
    this->deleteFile(fileName);
    return false;
}

void FFmpegThread::initOption()
{
    //设置缓存大小(1080p可将值调大/现在很多摄像机是2k可能需要调大/一般2k是1080p的四倍)
    av_dict_set(&options, "buffer_size", "8192000", 0);
    //设置超时断开连接时间(单位微秒/3000000表示3秒)
    av_dict_set(&options, "stimeout", "3000000", 0);
    //设置最大时延(单位微秒/1000000表示1秒)
    av_dict_set(&options, "max_delay", "1000000", 0);
    //自动开启线程数
    av_dict_set(&options, "threads", "auto", 0);

    //通信协议采用tcp还是udp(udp优点是无连接/在网线拔掉以后十几秒钟重新插上还能继续接收/缺点是网络不好的情况下会丢包花屏)
    if (transport != "auto") {
        av_dict_set(&options, "rtsp_transport", transport.toUtf8().constData(), 0);
    }

    //开启无缓存(rtmp等视频流不建议开启)
    //av_dict_set(&options, "fflags", "nobuffer", 0);
    //av_dict_set(&options, "fflags", "discardcorrupt", 0);

    //有些视频网站根据这个头部消息过滤不让ffmpeg访问需要模拟成其他的
    //av_dict_set(&options, "user_agent", "libmpv", 0);
    av_dict_set(&options, "user_agent", "Mozilla", 0);

    //增加rtp/sdp支持(后面发现不要加)
    if (videoUrl.endsWith(".sdp")) {
        //av_dict_set(&options, "protocol_whitelist", "file,rtp,udp", 0);
    }

    //设置分辨率帧率等参数
    if (videoType == VideoType_Camera || videoType == VideoType_Desktop) {
        //设置分辨率
        if (bufferSize != "0x0") {
            av_dict_set(&options, "video_size", bufferSize.toUtf8().constData(), 0);
        }

        //设置帧率
        if (frameRate > 0) {
            av_dict_set(&options, "framerate", QString::number(frameRate).toUtf8().constData(), 0);
        }

        //设置坐标XY以及是否采集鼠标指针
        if (videoType == VideoType_Desktop) {
            //av_dict_set(&options, "draw_mouse", "0", 0);
            //av_dict_set(&options, "show_region", "1", 0);

            int offsetX = this->property("offsetX").toInt();
            int offsetY = this->property("offsetY").toInt();
#ifdef Q_OS_WIN
            //windows上通过设置offset_x/offset_y来设置偏移值
            av_dict_set(&options, "offset_x", QString::number(offsetX).toUtf8().constData(), 0);
            av_dict_set(&options, "offset_y", QString::number(offsetY).toUtf8().constData(), 0);
#else
            //linux系统通过设备名称带上偏移值传入
            videoUrl += QString("+%1,%2").arg(offsetX).arg(offsetY);
#endif
        }

        //设置输入格式(具体要看设置是否支持)
        //后面改成了统一转成标准yuv420所以不用设置也没有任何影响
        //av_dict_set(&options, "input_format", "mjpeg", 0);
    }

    //如果设置了秘钥则需要启用解密
    if (!secretKey.isEmpty()) {
        QByteArray cryptoKey = this->property("cryptoKey").toByteArray();
        av_dict_set(&options, "decryption_key", cryptoKey.constData(), 0);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最全软件测试面试八股文(答案+文档+视频讲解)

Part1 1、你的测试职业发展是什么&#xff1f; 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自…

【C语言】指针的进阶(三)—— 模拟实现qsort函数以及指针和数组的笔试题解析

目录 1、模拟实现qsort函数 1.1、qsort函数的回顾 1.2、模拟实现qsort函数 2、指针和数组笔试题解析 2.1、一维数组 2.2、字符数组 1、模拟实现qsort函数 1.1、qsort函数的回顾 要模拟实现qsort函数&#xff0c;就要了解清楚qsort函数的参数以及使用方式。 我们先回顾一…

PyTorch实战:实现Cifar10彩色图片分类

目录 前言 一、Cifar10数据集 class torch.utils.data.Dataset torch.utils.data.DataLoader 二、定义神经网络 普通神经网络: 定义损失函数和优化器 训练网络-Net CPU训练 模型准确率 ​编辑 GPU训练 训练网络-LeNet 模型准确率 点关注&#xff0c;防走丢&#x…

9月15日、9月18日上课内容 Zookeeper集群 + Kafka集群

Zookeeper 本章结构 Zookeeper 概述 Zookeeper 定义 *&#xff08;了解&#xff09; Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制 *****&#xff08;非常重要&#xff0c;需要掌握&#xff09; Zookeeper从设计模式…

用低代码开发工具高效构建企业门户

企业信息门户EIP是指将各种应用系统、数据资源和互联网资源统一集中&#xff0c;根据每个用户使用特点和角色的不同&#xff0c;形成个性化的应用界面&#xff0c;并通过对事件和消息的处理、传输把用户有机地联系在一起。 企业随着业务的发展&#xff0c;运作的复杂度也在不断…

第三十二章 Objects

[toc] 第三十二章 Objects Objects 对象类简介 IRIS 通过以下对象类提供对象技术&#xff1a; %Library.RegisteredObject、 %Library.Persistent %Library.SerialObject。 下图展示了这些类之间的继承关系&#xff0c;以及它们的一些参数和方法。 %Library 包的类名称可以…

Vite + Vue3 使用cdn引入依赖 vite cdn vue3 cdn vite引入cdn

Vite Vue3 使用cdn引入依赖 vite cdn vue3 cdn vite引入cdn 1、安装插件2、在 vite.config.js 引用3、main.js4、打包测试 1、安装插件 npm install element-plus --save2、在 vite.config.js 引用 import { defineConfig } from vite import vue from vitejs/plugin-vue// …

用开源代码构建机器人需要考虑的问题

导读或许你正在考虑&#xff08;或正在进行&#xff09;将机器人使用开源软件推向市场。这个机器人是基于 linux 构建的。也许你正在使用机器人操作系统&#xff08;ROS&#xff09;或任务导向操作套件&#xff08;MOOS&#xff09;&#xff0c;或者是另外一个可以帮助你简化开…

007 数据结构_堆——“C”

前言 本文将会向您介绍关于堆Heap的实现 具体步骤 tips&#xff1a;本文具体步骤的顺序并不是源代码的顺序 typedef int HPDataType; typedef struct Heap {HPDataType* _a;int _size;int _capacity; }Heap;初始化 void HeapCreate(Heap* hp, HPDataType* a, int n) {hp-&…

AT32F407裸机工程创建

1、建立工程文件夹 2、找到AT提供DEMO例程&#xff0c;我们需要复制相关的内核文件出来&#xff0c;到我们创建的这个文件夹 1)将库文件拿过来 2)内核文件 3)启动文件 我把F407相关的内核文件都复制过来&#xff0c;然后具体看自己使用哪个型号&#xff0c;工程自己添加对应的文…

避雷!这9本期刊已被剔除!9月SCI/SSCI目录已更新(附2023年WOS历次更新全目录)

2023年9月20日&#xff0c;科睿唯安更新了Web of Science核心期刊目录。 此次更新后SCIE期刊目录共包含9490本期刊&#xff0c;SSCI期刊目录共包含3552本期刊。此次SCIE & SSCI期刊目录更新&#xff0c;与上次更新&#xff08;2023年8月&#xff09;相比&#xff0c;共有9本…

共育电商人才,引领行业发展丨知了汇智与协作时代达成战略合作

随着新一轮科技革命和产业革命的深入发展&#xff0c;数字经济正在成为重塑全球经济结构、改变全球竞争格局的关键力量&#xff0c;数字经济与实体经济的深度融合&#xff0c;也将是未来经济发展的重要动力。数字经济的发展正在催生电子商务模式不断创新&#xff0c;新业态下企…

安防监控系统/视频云存储/视频监控平台EasyCVR无法级联上级平台,该如何解决?

安防视频监控系统EasyCVR平台能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#xff0c;也…

《动手学深度学习》(pytorch版+mxnet版)2023最新

我又来推书了&#xff0c;这次分享的这本书可是重量级&#xff0c;目前已经被55个国家300所大学用于教学&#xff0c;同时受到了学术界与工业界的强烈推荐。 这本书就是李沐、阿斯顿张、立顿、斯莫拉四位大佬联合编写的《动手学深度学习》。本书面向中文读者&#xff0c;能运行…

第二十四章 原理篇:DBB

上班真的好累哦&#xff01; 理论上应该从RepVGG开始写重参化的&#xff0c;而且上星期就打算写来着&#xff01; 但是上班真的好累哦完全提不起精神在周末打字看论文&#xff01; 参考教程&#xff1a; https://arxiv.org/pdf/2103.13425.pdf https://github.com/DingXiaoH/D…

自己实现一个简单的vhost-net

框架 vhost在网络中的位置如图&#xff1a; 要学习具体的框架可以看我之前的文章vhost-net--------深入了解Virtio-networking和vhost-net 接下来&#xff0c;我们自己实现一个vhost. vhost-net代码 在代码中写了详细注释&#xff0c;就直接上代码了 #include <stdio.h…

期权是什么?一分钟带你玩转期权策略!

很多人问我期权是什么&#xff0c;这个问题怎么回答呢&#xff1f;首先期权是一种交易模式&#xff0c;如同股票期货一样&#xff0c;但它又不同于股票和期货&#xff0c;因为它有自己的交易规则和特性&#xff0c;期权更多是一种工具&#xff0c;可以做空大盘对冲下跌风险&…

0018Java程序设计-springboot智慧环卫养管作业平台

文章目录 摘 要目 录系统设计开发环境 摘 要 本智慧环卫养管作业平台就是建立在充分利用现在完善科技技术这个理念基础之上&#xff0c;并使用IT技术进行对环卫养管作业的管理&#xff0c;从而保证环卫养管作业能够高效的进行&#xff0c;可以实现环卫养管作业的在线管理&…

健康云HIS系统源码,满足基层医疗机构业务需求,提供挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等功能

云his系统源码 二级医院HIS系统全套源代码 自主研发&#xff0c;自主版权 一款满足基层医疗机构各类业务需要的健康云HIS系统。该系统能帮助基层医疗机构完成日常各类业务&#xff0c;提供病患挂号支持、病患问诊、电子病历、开药发药、会员管理、统计查询、医生站和护士站等一…

wabp.m 代码注释(便于算法快速理解)

算法效果: 波峰和起点检测效果: function [r,pk] = wabp(Araw, Offset,Scale, Fs) % r = wabp(Araw,Offset,Scale, Fs); % Input: Araw (125Hz sampled) waveform in wfdb-MIT format, % Offset, Scale % Araw = 血压波形 % Offset=偏移(信号减去或者加上偏移恢复成…