Qt/C++音视频开发72-倍速推流/音视频同步倍速推流/不改变帧率和采样率/低倍速和高倍速
一、前言
最近多了个新需求,需要倍速推流,推流界的扛把子obs也有倍速推流功能,最高支持到两倍速。这里所说的倍速,当然只限定在文件,只有文件才可能有倍速功能,因为也只有文件才能倍速解码播放。实时视频流是不可能倍速的,因为没有时长,有时长的才可以按照播放进度来。是否是文件也不能通过是不是本地文件等来判断,以为很多http/rtsp/m3u8等也可能是文件,具体最终的判断依据应该是有没有时长,能不能获取到时长,能获取到的就说明是文件。
倍速推流和倍速播放功能相通,在ffmpeg做音视频解码常识中,有个pts和dts就是用来控制显示时间和解码时间的,如果这两个值除以2就说明时间少了一半,就是2倍速,乘以2就表示时间多了2倍,就是0.5倍速,基本上的运算公式就是 packet.pts = packet.pts/speed,其中这个speed速度参数是float类型。倍速播放的时候其实就是将收到的packet的pts/dts更改后,再送入解码,而推流其实就是保存,保存到rtsp地址就是将数据推流到rtsp,所以将这个值经过同样的运算发出去,就形成了倍速推流。
公众号:Qt实战,各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发。
公众号:Qt入门和进阶,专门介绍Qt/C++相关知识点学习,帮助Qt开发者更好的深入学习Qt。多位Qt元婴期大神,一步步带你从入门到进阶,走上财务自由之路。
二、效果图
三、体验地址
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
- 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_push。
- 视频主页:https://space.bilibili.com/687803542
四、功能特点
- 支持各种本地音视频文件和网络音视频文件,格式包括mp3、aac、wav、wma、mp4、mkv、rmvb、wmv、mpg、flv、asf等。
- 支持各种网络音视频流,网络摄像头,协议包括rtsp、rtmp、http等。
- 支持本地摄像头设备推流,可指定分辨率、帧率、格式等。
- 支持本地桌面采集推流,可指定屏幕索引、采集区域、起始坐标、帧率等,也支持指定窗口标题进行采集。
- 可实时切换预览视频文件,可切换音视频文件播放进度,切换到哪里就推流到哪里。预览过程中可以切换静音状态和暂停推流。
- 可指定重新编码推流,任意源头格式可选强转264或265格式。
- 可转换分辨率推流,设置等比例缩放或者指定分辨率进行转换。
- 推流的清晰度、质量、码率都可调,可以节约网络带宽和拉流端的压力。
- 音视频文件自动循环不间断推流。
- 音视频流有自动掉线重连机制,重连成功自动继续推流。
- 支持各种流媒体服务程序,包括但不限于mediamtx、ZLMediaKit、srs、LiveQing、nginx-rtmp、EasyDarwin、ABLMediaServer。
- 通过配置文件自动加载对应流媒体程序的协议和端口,自动生成推流地址和各种协议的拉流地址。可以通过配置文件自己增加流媒体程序。
- 可选rtmp、rtmp格式推流,推流成功后,支持多种格式拉流,包括但不限于rtsp、rtmp、hls、flv、ws-flv、webrtc等。
- 在软件上推流成功后,可以直接单击网页预览,实时预览推流后拉流的画面,多画面网页展示。
- 软件界面上可单击对应按钮,动态添加文件和目录,可手动输入地址。
- 推拉流实时性极高,延迟极低,延迟时间大概在100ms左右。
- 极低CPU资源占用,4路主码流推流只需要占用0.2%CPU。理论上常规普通PC机器推100路毫无压力,主要性能瓶颈在网络。
- 可以推流到外网服务器,然后通过手机、电脑、平板等设备播放对应的视频流。
- 每路推流都可以手动指定唯一标识符(方便拉流/用户无需记忆复杂的地址),没有指定则按照策略随机生成hash值。也支持自动按照指定标识后面加数字的方式递增命名。比如设置标识为字母v,策略为标识递增,则每添加一个对应的推流码命名依次是v1、v2、v3等。
- 根据推流协议自动转码格式,默认策略按照选择的推流协议,比如rtsp支持265而rtmp不支持,如果是265的文件而选择rtmp推流,则自动转码成264格式再推流。
- 音视频同步推流,在拉流和采集的时候就会自动处理好同步,同步后的数据再推流。
- 表格中实时显示每一路推流的分辨率和音视频数据状态,灰色表示没有输入流,黑色表示没有输出流,绿色表示原数据推流,红色表示转码后的数据推流。
- 自动重连视频源,自动重连流媒体服务器,保证启动后,推流地址和打开地址都实时重连,只要恢复后立即连上继续采集和推流。
- 根据不同的流媒体服务器类型,自动生成对应的rtsp、rtmp、hls、flv、ws-flv、webrtc拉流地址,用户可以直接复制该地址到播放器或者网页中预览查看。
- 添加的推流地址等信息自动存储到文件,可以手动打开进行修改,默认启动后自动加载历史记录。
- 可以指定生成的网页文件保存位置,方便作为网站网页发布,可以直接在浏览器中输入网址进行访问,发布后可以直接在局域网其他设备比如手机或者电脑打开对应网址访问。
- 可选是否开机启动、后台运行等。网络推流添加的rtsp地址可勾选是否隐藏地址中的用户信息。
- 自带设备推流模块,自动识别本地设备,包括本地的摄像头和桌面,可以手动选择不同的是视频和音频采集设备进行推流。
- 自带文件点播模块,添加文件后用户可以拉取地址点播,用户端可以任意切换播放进度。支持各种浏览器(谷歌chromium、微软edge、火狐firefox等)、各种播放器(vlc、mpv、ffplay、potplayer、mpchc等)打开请求。
- 文件点播模块实时统计显示每个文件对应的访问数量、总访问数量、不同IP地址访问数量。
- 文件点播模块采用纯QTcpSocket通信,不依赖流媒体服务程序,核心源码不到500行,注释详细,功能完整。
- 支持任意Qt版本(Qt4、Qt5、Qt6),支持任意系统(windows、linux、macos、android、嵌入式linux等)。
五、相关代码
#include "frmspeedpush.h"
#include "ui_frmspeedpush.h"
#include "qthelper.h"
#include "videoutil.h"
frmSpeedPush::frmSpeedPush(QWidget *parent) : QWidget(parent), ui(new Ui::frmSpeedPush)
{
ui->setupUi(this);
this->initForm();
this->initConfig();
}
frmSpeedPush::~frmSpeedPush()
{
AppConfig::SpeedPushStart = (ui->btnStart->text() == "停止推流");
AppConfig::writeConfig();
delete ui;
}
void frmSpeedPush::initForm()
{
VideoPara videoPara = ui->videoWidget->getVideoPara();
videoPara.videoCore = VideoCore_FFmpeg;
ui->videoWidget->setVideoPara(videoPara);
VideoPara para = ui->videoWidget->getVideoPara();
para.playRepeat = true;
ui->videoWidget->setVideoPara(para);
connect(ui->videoWidget, SIGNAL(sig_receivePlayStart(int)), this, SLOT(receivePlayStart(int)));
connect(ui->videoWidget, SIGNAL(sig_receivePlayFinsh()), this, SLOT(receivePlayFinsh()));
}
void frmSpeedPush::initConfig()
{
VideoUtil::loadMediaUrl(ui->cboxMediaUrl, AppConfig::SpeedMediaUrl, 0x40);
connect(ui->cboxMediaUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
ui->txtPushUrl->setText(AppConfig::SpeedPushUrl);
connect(ui->txtPushUrl, SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
VideoUtil::loadSpeed(ui->cboxSpeed);
ui->cboxSpeed->setCurrentIndex(ui->cboxSpeed->findData(AppConfig::SpeedPushValue));
connect(ui->cboxSpeed, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
ui->ckMuted->setChecked(AppConfig::SpeedPushMuted);
connect(ui->ckMuted, SIGNAL(stateChanged(int)), this, SLOT(saveConfig()));
if (AppConfig::SpeedPushStart) {
on_btnStart_clicked();
}
}
void frmSpeedPush::saveConfig()
{
AppConfig::SpeedMediaUrl = ui->cboxMediaUrl->currentText().trimmed();
AppConfig::SpeedPushUrl = ui->txtPushUrl->text().trimmed();
AppConfig::SpeedPushValue = ui->cboxSpeed->itemData(ui->cboxSpeed->currentIndex()).toFloat();
AppConfig::SpeedPushMuted = ui->ckMuted->isChecked();
AppConfig::writeConfig();
}
void frmSpeedPush::receivePlayStart(int time)
{
VideoThread *thread = ui->videoWidget->getVideoThread();
thread->setMuted(AppConfig::SpeedPushMuted);
thread->setSpeed(AppConfig::SpeedPushValue);
thread->setEncodeSpeed(AppConfig::SpeedPushValue);
thread->recordStart(AppConfig::SpeedPushUrl);
connect(thread, SIGNAL(receivePosition(qint64)), this, SLOT(receivePosition(qint64)));
ui->sliderPosition->setRange(0, thread->getDuration());
ui->btnStart->setText("停止推流");
ui->cboxSpeed->setEnabled(false);
}
void frmSpeedPush::receivePlayFinsh()
{
ui->sliderPosition->setRange(0, 0);
ui->btnStart->setText("启动推流");
ui->cboxSpeed->setEnabled(true);
}
void frmSpeedPush::receivePosition(qint64 position)
{
ui->sliderPosition->setValue(position);
}
void frmSpeedPush::on_btnStart_clicked()
{
if (ui->btnStart->text() == "启动推流") {
ui->videoWidget->open(AppConfig::SpeedMediaUrl);
} else {
ui->videoWidget->stop();
}
}
void frmSpeedPush::on_sliderPosition_clicked()
{
int value = ui->sliderPosition->value();
on_sliderPosition_sliderMoved(value);
}
void frmSpeedPush::on_sliderPosition_sliderMoved(int value)
{
ui->videoWidget->setPosition(value);
}
void frmSpeedPush::on_ckMuted_stateChanged(int arg1)
{
ui->videoWidget->setMuted(ui->ckMuted->isChecked());
}
void FFmpegSave::writePacket2(AVPacket *packet)
{
//非音视频流不用处理
int index = packet->stream_index;
if (index != videoIndexOut && index != audioIndexOut) {
return;
}
//转发数据包(可以设置仅仅转发数据包不用继续)
if (sendPacket) {
emit receivePacket(FFmpegHelper::creatPacket(packet));
if (onlySendPacket) {
return;
}
}
//封装格式 https://blog.csdn.net/weixin_44520287/article/details/113435440 https://xilixili.net/2018/08/20/ffmpeg-got-raw-h264/
//测试发现部分文件如果是非编码保存也写入了/可能部分播放器不支持保存后的文件播放/比如安卓上
if (index == videoIndexOut) {
FFmpegSaveHelper::writeBsf(packet, videoStreamIn, bsfCtx);
}
if (saveVideoType == SaveVideoType_Stream) {
//只需要写入视频数据
if (index == videoIndexOut) {
file.write((char *)packet->data, packet->size);
}
} else if (saveVideoType == SaveVideoType_Mp4) {
//取出输入输出流的时间基
AVStream *streamIn = (index == videoIndexOut ? videoStreamIn : audioStreamIn);
AVStream *streamOut = formatCtx->streams[index];
AVRational timeBaseIn = streamIn->time_base;
AVRational timeBaseOut = streamOut->time_base;
//转换时间基准
if (index == videoIndexOut) {
FFmpegSaveHelper::rescalePacket(packet, timeBaseIn, videoCount, frameRate);
FFmpegSaveHelper::rescalePacket(packet, timeBaseIn, timeBaseOut);
} else if (index == audioIndexOut) {
if (audioEncode) {
FFmpegSaveHelper::rescalePacket(packet, audioDuration);
} else {
FFmpegSaveHelper::rescalePacket(packet, timeBaseIn, timeBaseOut, audioDuration);
}
}
//打印对应的信息方便查看/videoIndexOut/audioIndexOut
if (index == -1) {
qDebug() << TIMEMS << flag << index << packet->pts << packet->dts << packet->duration;
}
//倍速调整时间戳
if (encodeSpeed != 1) {
packet->pts = packet->pts / encodeSpeed;
packet->dts = packet->dts / encodeSpeed;
}
//写入一帧数据/如果用 av_interleaved_write_frame 默认会缓存/可能导致音频越来越慢
int result = av_write_frame(formatCtx, packet);
if (result < 0) {
errorCount++;
debug(result, QString("写%1包").arg(index == audioIndexOut ? "音频" : "视频"), "");
} else {
errorCount = 0;
}
//推流超过错误次数需要重连
if (errorCount >= 5 && saveMode != SaveMode_File) {
isOk = false;
errorCount = 0;
emit receiveSaveError(VideoError_Save);
}
}
}
Qt/C++音视频开发72-倍速推流/音视频同步倍速推流/不改变帧率和采样率/低倍速和高倍速的更多相关文章
- Android IOS WebRTC 音视频开发总结(五五)-- 音视频通讯中的抗丢包与带宽自适应原理
本文主要分析webrtc中的抗丢包与带宽自适应原理,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help 文章内容主要来自中国电信北京研究院丁博士在 ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
- Android开发 音视频开发需要了解的专业术语知识
前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...
- Python音视频开发:消除抖音短视频Logo的图形化工具实现
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- 【秒懂音视频开发】02_Windows开发环境搭建
音视频开发库的选择 每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如: iOS:AVFoundation.AudioUnit等 Android:MediaPlayer.Med ...
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android IOS WebRTC 音视频开发总结(五九)-- webrtc这蛋糕都怎么吃?
本文主要介绍webrtc应用状况,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号blackerteam,更多详见www.blackerteam.com WebRTC是个好东东,就好比是 ...
随机推荐
- C# 中的四种整形数据
// C# 中有四种整数类型 byte short int long byte bMax = byte.MaxValue; /// 255 最大值 byte bMin = byte.MinValue; ...
- yarn : 无法加载文件 C:\Users\zhulo\AppData\Roaming\npm\yarn.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?Li nkID=135170 中的 about_Execution_Policies。 所在位置 行:1 字符: 1 + yarn serve
powershell的执行策略问题: 解决办法: 管理员身份打开powershell 输入 set-ExecutionPolicy RemoteSigned 然后选择 a or Y :
- manim边做边学--数轴
数轴是数学中的一个基本概念,它规定了原点.正方向和单位长度的直线. Manim中的NumberLine就是一个专门用来表示数轴的对象,它允许用户设置数轴的范围.间隔和显示长度等参数,从而灵活地在动画中 ...
- Nuxt.js 应用中的 builder:watch 事件钩子详解
title: Nuxt.js 应用中的 builder:watch 事件钩子详解 date: 2024/10/24 updated: 2024/10/24 author: cmdragon excer ...
- freeswitch的话单处理
概述 freeswitch是一款简单好用的VOIP开源软交换平台. 如果对cdr话单要求不高,可以直接使用fs的原始话单文件,使用脚本做一些简单的统计. 环境 CentOS 7.9 freeswitc ...
- Mysql(2)—SQL语法详解(通俗易懂)
一.关于SQL 1.1 简介 SQL(Structured Query Language,结构化查询语言)是一种用于管理关系型数据库的标准编程语言.它主要用于数据的查询.插入.更新和删除等操作.SQL ...
- [Flink/FlinkCDC] 实践总结:Flink 1.12.6 升级 Flink 1.15.4
Flink DataStream/API 依赖模块的变化 版本变化 flink.version : 1.12.6 => 1.15.4 flink.connector.version : 1.12 ...
- ESP8266 + MQTT (platformio 开发环境)加用户名和密码
ESP8266 + MQTT git 地址: https://gitee.com/zhudachangs/esp8266-mqtt.git (如果无法打开说明在审核) 引用库 include < ...
- 使用VSCode进行WSL2的本机调试
首先我们需要安装Remote Development插件(这个Remote-WSL一定要保证是装上的哦). 然后我们先连接到WSL. (第一次进入远程模式,会慢一些,需要下载一些组件) (如果你打开这 ...
- KTL (0.9.2,通达信mdt文件)
K,K线,Candle蜡烛图. T,技术分析,工具平台 L,公式Language语言使用c++14,Lite小巧简易. 项目仓库:https://github.com/bbqz007/KTL 国内仓库 ...