一、前言

本功能最初也是有一些人提过类似的需求,就是能不能将本地的音视频文件,通过纯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. EDGE 浏览器占用内存优化

    windows + s 搜索 service 打开服务 : 找到下面 edge 三项 双击 把启动类型都改成 手动触发

  2. 016 Python 中的基本运算符

    #!/usr/bin/env python # -*- coding:utf-8 -*- # Datatime:2022/7/28 15:01 # Filename:016 Python 中的基本运算 ...

  3. 001 (Python+水论文合集)为什么录这个合集,这个合集会讲哪些内容?

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  4. 2.flask 源码解析:应用启动流程

    目录 一.flask 源码解析:应用启动流程 1.1 WSGI 1.2 启动流程 Flask 源码分析完整教程目录:https://www.cnblogs.com/nickchen121/p/1476 ...

  5. spring cloud openfeign 源码

    一.读取注解信息 入口 1 import org.springframework.boot.SpringApplication; 2 import org.springframework.boot.a ...

  6. 饿了么Element UI之Upload组件图片上传【原创】

    图片文件换汤不换药,只要注意前端的写法即可 1.饿了么组件可以利用 http-request 的属性对上传进行自定义 :http-request="uploadFile" 2.设置 ...

  7. ESP8266+ MQTT+SG90(舵机) platformio

    ESP8266 + MQTT + SG90(舵机) platformio 连线 ESP8266 MG90S(舵机) GND 棕色 VCC 红色 模拟引脚 橙色 源代码 https://gitee.co ...

  8. win10启用长路径

    方法一:操作组策略 Win+R 输入 gpedit.msc 依次点击[计算机配置]->[管理模板]->[系统]->[文件系统],找到 "启用win32长路径" 并 ...

  9. 鸿蒙NEXT开发案例:光强仪

    [引言] 本文将介绍如何使用鸿蒙NEXT框架开发一个简单的光强仪应用,该应用能够实时监测环境光强度,并给出相应的场景描述和活动建议. [环境准备] 电脑系统:windows 10 开发工具:DevEc ...

  10. delphi BDE Reader 不需要驱动

    用过Delphi开发的几乎都知道BDE,是读取paradox DB (*.db)数据库(表)读取的驱动. 要存取数据,必需安装 BDE驱动程序,才能正常读取,还需要配置,发布程序就更不方便,所以吐槽的 ...