一、前言

本功能最初也是有一些人提过类似的需求,就是能不能将本地的音视频文件,通过纯Qt程序推流出去,然后用户可以直接在网页上播放,也可以用各种播放器播放,然后还可以任意切换播放进度,其实说白了就是个文件服务器,用户通过网络地址访问以后,告诉对方当前是媒体文件就会自动播放,是其他文件则可以开启下载,很多视频网站最初也是按照这个思路来设计,当然缺点很明显,那就是无法防止用户下载,毕竟这个本来就是当做文件发给用户的,无所谓保密的需求,话说现在的无论哪一种视频网站,只要能播放,用户就能通过各种手段录制下来的,也是无法规避这个问题。

无论网络协议如何发展,都离不开最底层的两种协议,tcp/udp通信,http也是建立在这两种协议基础上,然后又在http基础上衍生了众多的协议,总之,最基础的tcp/udp几十年都没变过,现在音视频发展这么迅速,衍生的各种rtmp/rtsp/hsl/webrtc啥的,最终底层还是基于tcp/udp通信,明白了这个道理,文件推流理论上基于tcp就可以实现。音视频文件在普通文件服务的基础上还多了个范围的参数Accept-Ranges: bytes/Content-Range,就是用户单击了进度后告诉服务这边当前要切换到哪个字节位置,这样就可以任意跳转播放进度。

二、效果图





三、体验地址

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

四、相关代码

void FilePushClient::readData()
{
//GET /后缀 HTTP/1.1
//Host: 192.168.0.110:6908
//Connection: keep-alive (一般网页请求是keep-alive/其他都是close)
//Upgrade-Insecure-Requests: 1
//User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
//Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
//Accept-Encoding: gzip, deflate
//Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 QByteArray data = tcpSocket->readAll();
buffer.append(data); //超过了长度说明数据是垃圾数据
if (buffer.size() > 1000) {
buffer.clear();
return;
} //末尾必须是两个回车换行
if (!buffer.endsWith("\r\n\r\n")) {
return;
} //解析请求(解析失败则不用继续)
QHttpParser parser;
bool ok = parser.parserRequest(buffer);
emit receiveData(buffer);
buffer.clear();
if (!ok) {
quit();
return;
} //不是对应的方法
if (parser.method() != "GET") {
quit();
return;
} //取出后缀地址(如果是请求图标则不用继续)
QString url = parser.url();
if (!url.startsWith("/") || url.startsWith("/favicon.ico")) {
return;
} //根据请求中的hash值查找文件
QString hash = url.mid(1, url.length());
FilePushServer *server = (FilePushServer *)this->parent();
QString fileName = server->findFile(hash);
if (!this->setFile(fileName)) {
quit();
return;
} QString range = parser.headerValue("Range");
if (range.isEmpty()) {
this->writeData200(0);
return;
} //Range: bytes=0- / bytes=-1024 / bytes=0-1024
QStringList list = range.split("=");
if (list.count() != 2) {
quit();
return;
} //取出进度范围
range = list[1];
range.replace(" ", "");
list.clear();
list = range.split("-"); //测试下来发现基本上都是 x- 的情况
qint64 startPos, endPos;
if (range.startsWith("-")) {
endPos = fileSize - 1;
startPos = endPos - list.at(0).toInt();
} else if (range.endsWith("-")) {
startPos = list.at(0).toInt();
endPos = fileSize - 1;
} else {
startPos = list.at(0).toInt();
endPos = list.at(1).toInt();
} this->writeData206(startPos, endPos);
} void FilePushClient::writeData(qint64 bytes)
{
writeByteCount -= bytes;
if (tcpSocket && writeByteCount > 0) {
qint64 size = 512 * 1024;
size = tcpSocket->write(file->read(size));
//qDebug() << TIMEMS << "writeData" << size;
}
} QByteArray FilePushClient::getHeadData(const QString &flag, qint64 startPos, qint64 endPos, qint64 bufferSize)
{
QStringList list;
list << flag;
list << "Server: QQ_517216493 WX_feiyangqingyun";
list << "Cache-control: no-cache";
list << "Pragma: no-cache";
list << "Connection: close";
list << "Accept-Ranges: bytes";
list << "Access-Control-Allow-Origin: *";
list << QString("Content-Type: %1").arg(fileType);
list << QString("Content-Length: %1").arg(bufferSize);
if (playMode == 1) {
list << QString("Content-Disposition: attachment;filename=%1").arg(fileName);
}
list << QString("Content-Range: bytes %1-%2/%3").arg(startPos).arg(endPos).arg(fileSize);
//末尾必须加个回车换行
list << "\r\n"; QString data = list.join("\r\n");
return data.toUtf8();
} void FilePushClient::writeData200(qint64 startPos)
{
if (!file->isOpen()) {
return;
} if (startPos >= fileSize) {
return;
} //文件切换到对应位置
file->seek(startPos);
qint64 endPos = fileSize - 1;
qint64 bufferSize = fileSize - startPos;
QByteArray data = getHeadData("HTTP/1.1 200 OK", startPos, endPos, bufferSize); //计算并发送数据
writeByteCount = data.size() + (fileSize - startPos);
tcpSocket->write(data);
emit sendData(data);
//qDebug() << TIMEMS << "writeData200";
} void FilePushClient::writeData206(qint64 startPos, qint64 endPos)
{
if (!file->isOpen()) {
return;
} if (startPos >= fileSize || startPos >= endPos) {
return;
} //文件切换到对应位置
file->seek(startPos);
qint64 bufferSize = endPos - startPos + 1;
QByteArray data = getHeadData("HTTP/1.1 206 Partial Content", startPos, endPos, bufferSize); //计算并发送数据
writeByteCount = data.size() + (fileSize - startPos);
tcpSocket->write(data);
emit sendData(data);
//qDebug() << TIMEMS << "writeData206";
}

五、功能特点

5.1 文件推流

  1. 指定网卡和监听端口,接收网络请求推送音视频等各种文件。
  2. 实时统计显示每个文件对应的访问数量、总访问数量、不同IP地址访问数量。
  3. 可指定多种模式,0-直接播放、1-下载播放。
  4. 实时打印显示各种收发请求和应答数据。
  5. 每个文件对应MD5加密的唯一标识符,用于请求地址后缀区分访问哪个文件。
  6. 支持各种浏览器(谷歌chromium/微软edge/火狐firefox等)、各种播放器(vlc/mpv/ffplay/potplayer/mpchc等)打开请求。
  7. 播放过程中可以任意切换播放进度,支持倍速播放。
  8. 需要推流的文件名称历史记录自动存储和打开加载应用。
  9. 切换文件获取访问地址,自动拷贝地址到剪切板方便直接粘贴测试使用。
  10. 极低CPU占用,128路1080P同时推流不到1%CPU占用,异步发送数据机制。
  11. 纯QTcpSocket通信,不依赖流媒体服务程序,核心源码不到500行,注释详细,功能完整。
  12. 支持Qt4/Qt5/Qt6任意版本,支持任意系统(windows/linux/macos/android/嵌入式linux等)。

5.2 网络推流

  1. 支持各种本地视频文件和网络视频文件。
  2. 支持各种网络视频流,网络摄像头,协议包括rtsp、rtmp、http。
  3. 支持将本地摄像头设备推流,可指定分辨率和帧率等。
  4. 支持将本地桌面推流,可指定屏幕区域和帧率等。
  5. 自动启动流媒体服务程序,默认mediamtx(原rtsp-simple-server),可选用srs、EasyDarwin、LiveQing、ZLMediaKit等。
  6. 可实时切换预览视频文件。
  7. 推流的清晰度和质量可调。
  8. 可动态添加文件、目录、地址。
  9. 视频文件自动循环推流,如果视频源是视频流,在掉线后会自动重连。
  10. 网络视频流自动重连,重连成功自动继续推流。
  11. 网络视频流实时性极高,延迟极低,延迟时间大概在100ms左右。
  12. 推流后除了用rtmp地址访问以外,还支持直接hls/webrtc访问,可以直接浏览器打开看实时画面。
  13. 支持Qt4/Qt5/Qt6任意版本,支持任意系统(windows/linux/macos/android/嵌入式linux等)。

Qt音视频开发41-文件推流(支持网页和播放器播放并切换进度)的更多相关文章

  1. Android 音视频开发(一):PCM 格式音频的播放与采集

    什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...

  2. WebRTC 音视频开发

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

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

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

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

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

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

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

  6. Android音视频开发(1):H264 基本原理

    前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...

  7. Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  8. Android IOS WebRTC 音视频开发总结(六)-- iOS开发之含泪经验

    前段时间在搞webrtc iOS开发,所以将标题改为了Android IOS WebRTC 音视频开发总结, 下面都是开发过程中的经验总结,转载请说明出处(博客园RTC.Blacker): 1. IO ...

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

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

  10. Android开发 音视频开发需要了解的专业术语知识

    前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...

随机推荐

  1. js自动调用 click 事件

    // 进入页面立即触发 (()=>{ // 兼容IE if(document.all) { document.getElementById("aid").click(); } ...

  2. Cookie、sessionStorage、localStorage的区别 ?

    共同点:都是保存在浏览器端的. 区别: 1.cookie数据始终携带在同源的http请求中,即cookie在浏览器和服务器间来回传递,而sessionStorage和Localstorage不会自动把 ...

  3. 混合云下的 Kubernetes 多集群管理与应用部署

    本文是上海站 Meetup 中讲师李宇根据其分享内容梳理成的文章 大家好,很高兴来到今天下午的 Meetup.我先简单做个自我介绍,我叫李宇,目前是 KubeSphere 的一名研发,主要负责多集群方 ...

  4. Ubuntu 22.04 解决和 Windows 共享蓝牙设备的问题

    我有一个 Airpods,连接到 WIndows 可以正常工作,但连接到 ubuntu 后会无法连接,只能删除设备选择重联,但是这又会导致 Windows 不能连接到耳机,只能也删除重新连接,费神费力 ...

  5. 生成文本聚类java实现1

    本章主要的学习是中文分词 和两种统计词频(传统词频和TF-IDF算法 ) 的方法. 学习目的:通过N多的新闻标题 or 新闻摘要 or 新闻标签,生成基本的文本聚类,以便统计当天新闻的热点内容. 扩展 ...

  6. 每日学学Java开发规范,OOP规约(附阿里巴巴Java开发手册(终极版))

    前言 每次去不同的公司,码不同的代码,适应不同的规范,经常被老大教育规范问题,我都有点走火入魔的感觉,还是要去看看阿里巴巴Java开发规范,从中熟悉一下,纠正自己,码出高效,码出质量. 想细看的可以去 ...

  7. 2.12 Linux两种远程管理工具(PuTTY和SecureCRT)

    通过<Linux远程管理协议>一节可以知道,Linux远程管理服务器多基于 SSH 协议.本节给大家介绍 2 种常见的基于 SSH 协议的远程管理工具,分别是 PuTTY 和 Secure ...

  8. 2.8 忘记root账户密码怎么办?

    Linux 的单用户模式有些类似 Windows 的安全模式,只启动最少的程序用于系统修复.在单用户模式(运行级别为 1)中,Linux 引导进入根 shell,网络被禁用,只有少数进程运行. 单用户 ...

  9. Minio安装以及使用

    Minio介绍 MinIO 是一个基于Apache License v2.0开源协议的对象存储服务.适合于存储大容量非结构化的数据,例如图片.视频.日志文件.备份数据和容器/虚拟机镜像等,而一个对象文 ...

  10. 灵活轻巧的java接口自动化测试实战

    前言 无论是自动化测试还是自动化部署,撸码肯定少不了,所以下面的基于java语言的接口自动化测试,要想在业务上实现接口自动化,前提是要有一定的java基础. 如果没有java基础,也没关系.这里小编也 ...