基于RK3568/RK3588/全志H3/飞腾芯片/音视频通话程序/语音对讲/视频对讲/实时性好/极低延迟

一、前言说明

近期收到几个需求都是做音视频通话,很多人会选择用webrtc的方案,这个当然是个不错的方案,但是依赖的东西太多,而且相关组件代码量很大,开发难度大。所以最终选择自己属性的方案,那就是推流拉流,采集端负责采集本地摄像头或者桌面,编码推流到流媒体服务器,然后要拉取对方的视音频,就是播放对应的rtsp地址即可,其实也可以是rtmp等地址,一般流媒体服务程序还提供各种http/flv等格式的拉流,方便各种场景需求,比如网页上可以直接播放flv或者webrtc的流。

为了使得使用更方便,还特意增加了可自定义悬浮画面位置,指定左上角、右上角、左下角、右下角、自定义位置和大小。还支持固定画中画功能,可交换主画面和浮窗画面,可设置画面左右排列等布局方式。考虑到客户的实际需求,还支持自定义水印,包括文字和图片水印,支持多个水印,指定任意位置。

二、效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、相关代码

#include "frmconfig.h"
#include "frmmain.h"
#include "ui_frmmain.h"
#include "qthelper.h"
#include "apphelper.h"
#include "osdgraph.h"
#include "ffmpegthread.h"
#include "ffmpegthreadcheck.h"frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain)
{ui->setupUi(this);this->initForm();this->installEventFilter(this);QMetaObject::invokeMethod(this, "formChanged", Qt::QueuedConnection);
}frmMain::~frmMain()
{delete ui;
}void frmMain::savePos()
{AppConfig::FormMax = this->isMaximized();if (!AppConfig::FormMax) {AppConfig::FormGeometry = this->geometry();}AppConfig::writeConfig();
}bool frmMain::eventFilter(QObject *watched, QEvent *event)
{//尺寸发生变化或者窗体移动位置记住窗体位置int type = event->type();if (type == QEvent::Resize || type == QEvent::Move) {QMetaObject::invokeMethod(this, "savePos", Qt::QueuedConnection);} else if (type == QEvent::Close) {audioInput->stop(false);audioOutput->stop(false);exit(0);}//尺寸发生变化重新调整小预览窗体的位置if (this->isVisible() && type == QEvent::Resize) {this->formChanged();}return QWidget::eventFilter(watched, event);
}void frmMain::initForm()
{//初始化输入输出视频控件int decodeType = AppConfig::DecodeType;AppHelper::initVideoWidget(ui->videoInput, decodeType);AppHelper::initVideoWidget(ui->videoOutput, decodeType);//初始化输入输出音频线程audioInput = new FFmpegThread(this);audioOutput = new FFmpegThread(this);checkInput = new FFmpegThreadCheck(audioInput, this);AppHelper::initAudioThread(audioInput, ui->levelInput, decodeType);AppHelper::initAudioThread(audioOutput, ui->levelOutput, decodeType);//输入打开成功后立即推流connect(audioInput, SIGNAL(receivePlayStart(int)), this, SLOT(receivePlayStart(int)));connect(ui->videoInput, SIGNAL(sig_receivePlayStart(int)), this, SLOT(receivePlayStart(int)));ui->ckInput->setChecked(AppConfig::MuteInput ? Qt::Checked : Qt::Unchecked);ui->ckOutput->setChecked(AppConfig::MuteOutput ? Qt::Checked : Qt::Unchecked);if (AppConfig::StartServer) {on_btnStart_clicked();}
}void frmMain::clearLevel()
{ui->levelInput->setLevel(0);ui->levelOutput->setLevel(0);
}void frmMain::formChanged()
{AppHelper::changeWidget(ui->videoInput, ui->videoOutput, ui->gridLayout, NULL);
}void frmMain::receivePlayStart(int time)
{QObject *obj = sender();if (obj == ui->videoInput) {
#ifdef betaversionOsdGraph::testOsd(ui->videoInput);
#endifui->videoInput->recordStart(AppConfig::VideoPush);} else if (obj == audioInput) {audioInput->recordStart(AppConfig::AudioPush);}
}void frmMain::on_btnStart_clicked()
{if (ui->btnStart->text() == "启动服务") {if (AppConfig::VideoUrl == "video=" || AppConfig::AudioUrl == "audio=") {QtHelper::showMessageBoxError("请先打开系统设置, 选择对应的视音频设备");//return;}ui->videoInput->open(AppConfig::VideoUrl);ui->videoOutput->open(AppConfig::VideoPull);audioInput->setMediaUrl(AppConfig::AudioUrl);audioOutput->setMediaUrl(AppConfig::AudioPull);audioInput->play();audioOutput->play();checkInput->start();ui->btnStart->setText("停止服务");} else {ui->videoInput->stop();ui->videoOutput->stop();audioInput->stop();audioOutput->stop();checkInput->stop();ui->btnStart->setText("启动服务");QMetaObject::invokeMethod(this, "clearLevel", Qt::QueuedConnection);}AppConfig::StartServer = (ui->btnStart->text() == "停止服务");AppConfig::writeConfig();
}void frmMain::on_btnConfig_clicked()
{static frmConfig *config = NULL;if (!config) {config = new frmConfig;connect(config, SIGNAL(formChanged()), this, SLOT(formChanged()));}config->show();config->activateWindow();
}void frmMain::on_ckInput_stateChanged(int arg1)
{bool muted = (arg1 != 0);audioInput->setMuted(muted);AppConfig::MuteInput = muted;AppConfig::writeConfig();
}void frmMain::on_ckOutput_stateChanged(int arg1)
{bool muted = (arg1 != 0);audioOutput->setMuted(muted);AppConfig::MuteOutput = muted;AppConfig::writeConfig();
}

四、相关地址

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

五、功能特点

  1. 支持局域网和外网音视频实时通话,延迟极低,资源占用极低。
  2. 自动获取本地所有视音频输入设备,本地摄像头设备自动罗列所有支持的分辨率、帧率、采集格式等信息。
  3. 可以指定采集的视频设备和音频输入设备,自由组合,视频设备可以设置不同的分辨率、帧率、采集格式。
  4. 支持本地桌面屏幕作为视频设备采集,支持多个屏幕,自动识别屏幕分辨率。
  5. 可以选择不同的声卡设备播放声音。
  6. 内置自动重连机制,视音频设备支持热插拔。
  7. 支持固定画中画功能,可交换主画面和浮窗画面,可设置画面左右排列等布局方式。
  8. 可自定义悬浮画面位置,指定左上角、右上角、左下角、右下角、自定义位置和大小。
  9. 内置流媒体服务程序,程序启动后自动启动流媒体服务,自动推拉流。
  10. 视音频流数据支持rtsp/rtmp/http/webrtc等方式拉流,可以直接网页上打开视频画面。
  11. 实时显示本地音频振幅和远程音量振幅,可以分别对输入输出音量设置静音,方便测试。
  12. 支持自定义水印,包括文字和图片水印,支持多个水印,指定任意位置。
  13. 支持不同的视音频设备组合,比如本地摄像头加电脑麦克风而不是摄像头的麦克风,比如本地电脑桌面屏幕加摄像头的麦克风等。
  14. 纯Qt+ffmpeg编写,支持windows和linux以及macos等系统,支持所有Qt版本、所有系统、所有编译器。
  15. 支持嵌入式linux板子和树莓派香橙派等,以及国产linux系统。

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

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

相关文章

AI+爆款文案,提示词脚本 ——卫朋

目录 简介 提示词 作者简介 简介 用好AI的前提是脑子里面要有框架。 AI就像是一个刚出生的小孩,没有判断力,疯狂接收世界上的各类信息。 如果没有从小的规则框架约束、没有道德约束,最终的结果就一定是混乱无序的。 AI也是一样&#x…

芯片:数字时代的算力引擎——鲲鹏、升腾、海光、Intel 全景解析

在大模型爆炸的时代,芯片如同现代文明的“数字心脏”,驱动着从智能手机、数据中心到人工智能和超级计算的每一个关键进程。在这场算力竞赛中,华为鲲鹏、升腾、海光以及行业巨头Intel各自扮演着独特而至关重要的角色。本文将深入解析这些核心算…

传输层协议TCP(上)

上一篇https://blog.csdn.net/Small_entreprene/article/details/148143494?fromshareblogdetail&sharetypeblogdetail&sharerId148143494&sharereferPC&sharesourceSmall_entreprene&sharefromfrom_link 上文学习了传输层的协议之一UDP,接下来…

关于ios点击分享自动复制到粘贴板的问题

前言 Android 系统没有什么特别的要求,实现这个也比较容易。但ios在某些情况下就会出现问题。 如果ios是点击之后,请求接口,再把接口的内容赋值给粘贴板肯定行不通,会被ios系统拦截,导致赋值失败或者赋值为空。建议使…

SAP Business One:无锡哲讯科技助力中小企业数字化转型的智慧之选

数字化转型,中小企业的必经之路 在当今竞争激烈的商业环境中,数字化转型已不再是大型企业的专利,越来越多的中小企业开始寻求高效、灵活的管理系统来优化业务流程、提升运营效率。作为全球领先的企业管理软件,SAP Business One…

【孙悟空喝水】2022-2-7

缘由C编程问题求解:9634: 孙悟空喝水-编程语言-CSDN问答 void 孙悟空喝水() {//缘由https://ask.csdn.net/questions/7639865?spm1005.2025.3001.5141int x 2&#xff0c; n 0; double s 0, ss 0;std::cin >> n;while ((int)s < n)s 1.0 / x, ss (x - 1.0) / …

OCC笔记:BRepMesh_IncrementalMesh的使用

1. 函数接口 2. 线性偏转与角度偏转 2.1. theLineDeflection&#xff1a;线性偏转 根据文档推导下 isRelative传入Standard_True时&#xff0c;theLineDeflection为相对值。 参看isRelative说明 //! param isRelative if TRUE deflection used for discretization of //! ea…

Visual Studio+SQL Server数据挖掘

这里写自定义目录标题 工具准备安装Visual studio 2017安装SQL Server安装SQL Server Management Studio安装analysis service SSMS连接sql serverVisual studio新建项目数据源数据源视图挖掘结构部署模型设置挖掘预测 部署易错点 工具准备 Visual studio 2017 analysis servi…

如何迁移SOS数据库和修改sos服务的端口号

一. 迁移SOS数据库。 1. 对SOS整个库进行拷贝。压缩拷贝等都可以 2. 找到SOS安装目录下的这个目录 /SOS7/SERVERS7/LOCAL/ 在此目录下会发现&#xff0c;有SOS服务库的文件夹。拷贝你要迁移的SOS数据库 3. 进入该文件夹&#xff0c;找到&#xff1a;serverdb.cfg 打开后&…

Oracle向PG转移建议以及注意点

Oracle向PG转移建议以及注意点 ✅ 一、语法差异与迁移建议 1. 包结构&#xff08;Package&#xff09; Oracle 支持 PACKAGE 和 PACKAGE BODY 分离定义。PostgreSQL 不支持包结构&#xff0c;需将每个函数/过程单独定义。 迁移建议&#xff1a; 将 PACKAGE 包中的每个函数…

PCIe-PCI、PCIe中断机制概述

PCI、PCIe中断概述 PCIe 中断机制在继承 PCI 传统中断&#xff08;INTx&#xff09;的基础上&#xff0c;引入了更高效的 MSI/MSI-X 方案&#xff0c;以提升设备性能并减少 CPU 轮询开销。以下是核心要点及技术演进&#xff1a; ⚙️ ​​一、PCIe 中断类型与演进​​ ​​IN…

改进自己的图片 app

1. 起因&#xff0c; 目的: 前面我写过一个图片 app &#xff0c; 最新做了些改动。 把原来的一列&#xff0c;改为3列&#xff0c; 继续使用瀑布流手机上使用&#xff0c;更流畅&#xff0c;横屏显示为2列。 2. 先看效果 3. 过程: 过程太细碎了&#xff0c;这里只是做一下…

【HTML-15】HTML表单:构建交互式网页的基石

表单是HTML中最强大的功能之一&#xff0c;它允许网页收集用户输入并与服务器进行交互。无论是简单的搜索框、登录页面&#xff0c;还是复杂的多步骤调查问卷&#xff0c;表单都是实现这些功能的核心元素。本文将深入探讨HTML表单的各个方面&#xff0c;帮助您构建高效、用户友…

关于智能体接入后端,在Apifox能够传参数给智能体的测试

from flask import Flask, request, jsonify, render_template import requests import json # 用于解析嵌套的 JSON 字符串app Flask(__name__)COZE_BOT_ID 7508736911423963162 COZE_API_KEY pat_cHXqrFzcvtktfmmlp4pjF3O2qmjioQW46uU8UNbUugyvSlFZclklpunc53DbR8ws COZE…

SQL进阶之旅 Day 8:窗口函数实用技巧

【SQL进阶之旅 Day 8】窗口函数实用技巧 在现代数据库开发中&#xff0c;处理复杂的业务逻辑和大规模数据时&#xff0c;仅仅依靠传统的GROUP BY和JOIN操作已经无法满足需求。**窗口函数&#xff08;Window Function&#xff09;**作为SQL标准的一部分&#xff0c;为开发者提供…

编译rustdesk,使用flutter、hwcodec硬件编解码

目录 安装相应的环境安装visual studio安装vpkg安装rust开发环境安装llvm和clang编译源码下载源码使用Sciter作为UI的(已弃用)使用flutter作为UI的(主流)下载flutter sdk桥接静默安装最近某desk免费的限制越来越多,实在没办法,平时远程控制用的比较多,只能用rustdesk了,…

由反汇编代码确定结构体的完整声明

C程序中遇到下面的代码 typedef struct {int left;a_struct a[CNT];int right; } b_struct;void test( int i, b_struct *bp) {int nbp->leftbp->right;a_struct *ap&bp->a[i];ap->x[ap->idx]n; } 下面是test函数的反汇编代码 结合C程序中的代码与test函数…

鸿蒙OSUniApp复杂表单与动态验证实践:打造高效的移动端表单解决方案#三方框架 #Uniapp

UniApp复杂表单与动态验证实践&#xff1a;打造高效的移动端表单解决方案 引言 在移动应用开发中&#xff0c;表单处理一直是一个既常见又具有挑战性的任务。随着HarmonyOS生态的蓬勃发展&#xff0c;越来越多的开发者开始关注跨平台解决方案。本文将深入探讨如何使用UniApp框…

Python学习(2) ----- Python的数据类型及其集合操作

在 Python 中&#xff0c;一切皆对象&#xff0c;每个对象都有类型。下面是 Python 中的常见内置类型分类和示例&#xff1a; &#x1f7e1; 1. 数字类型&#xff08;Numeric Types&#xff09; 类型说明示例int整数5, -42float浮点数3.14, -0.5complex复数1 2j a 10 …

深入解析Go语言数据类型:从底层到高级应用

引言 Go语言的数据类型系统设计体现了​​简洁性​​与​​高效性​​的完美平衡。作为静态编译型语言&#xff0c;Go提供了丰富的数据类型支持&#xff0c;从基础数值类型到高级并发原语&#xff0c;都经过精心设计。本文将深入剖析Go语言数据类型体系&#xff0c;揭示其底层…