基于arm64架构国产操作系统|Linux下的RTMP|RTSP低延时直播播放器开发探究

技术背景

2014年4月8日起,美国微软公司停止了对Windows XP SP3操作系统提供服务支持,这引起了社会和广大用户的广泛关注和对信息安全的担忧。而2020年对Windows7服务支持的终止再一次推动了国产系统的发展。工信部对此表示,将继续加大力度,支持Linux的国产操作系统的研发和应用,并希望用户可以使用国产操作系统。

为什么要发展国产操作系统?

  1. 技术自主性和信息安全:国家和政府机构通常认为拥有自主研发和掌握核心技术是保障国家信息安全和加强自主创新能力的重要举措。通过开发和商业化国产操作系统,可以降低对外国技术和软件的依赖,并减少潜在的信息泄露和安全风险。
  2. 降低技术依赖风险:依赖外国操作系统和软件可能面临技术封锁、供应中断或不稳定的问题。商业化国产操作系统可以减少对外部技术供应链的依赖,为国内企业和用户提供更可靠和稳定的软件解决方案,降低技术依赖风险。
  3. 满足国内市场需求:随着国内科技产业的快速发展,对于操作系统的需求也日益增长。国产操作系统可以更好地满足国内用户的需求,提供更贴近本地文化和习惯的用户界面和功能,提高用户的使用体验。
  4. 促进产业发展:国产操作系统的开发和应用可以带动相关产业的发展,包括硬件制造、软件开发、系统集成等。这有助于提升整个产业链的技术水平和竞争力,促进国内科技产业的升级和转型。
  5. 生态系统建设:发展国产操作系统有助于构建和完善自主可控的软件生态系统。通过鼓励和支持国内软件开发者在国产操作系统上进行应用开发,可以丰富应用生态,提高系统的可用性和易用性。

此外,随着云计算、大数据、人工智能等新兴技术的发展,操作系统作为基础设施的重要性日益凸显。发展国产操作系统可以为这些新兴技术提供更安全、更可靠的运行环境,推动相关产业的发展和创新。

综上所述,发展国产操作系统对于保障国家信息安全、降低技术依赖风险、满足国内市场需求、促进产业发展以及构建完善的生态系统等方面都具有重要意义。

技术实现

 顺势而为,在发布arm64架构的国产操作系统|Linux平台的RTMP|RTSP直播播放SDK之前,大牛直播SDK(官方)的直播播放SDK用一句比较流行的广告语叫遥遥领先,我们更是在前几年已经发布了Linux X86_64架构的播放器,并得到了广泛的应用。

 本次发布的可用于国产操作系统和Linux上的的RTMP|RTSP直播播放SDK, video输出基于X协议,audio输出采用PulseAudio和Alsa Lib实现。除了常规功能如实时静音、快照、buffer time设定、网络自动重连等,RTMP支持扩展H265播放(支持Enhanced RTMP H.265播放), RTSP也支持H265播放。

大牛直播SDK发布的Linux平台播放器SDK支持多实例播放,相关代码如下:

/** multi_player_demo.cpp* * Author: daniusdk.com** Copyright © 2017~2024 DaniuLive. All rights reserved.*/
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <poll.h>
#include <errno.h>#include <string>
#include <sstream>#include <X11/Xlib.h>
#include <X11/keysym.h>#include "nt_sdk_linux_smart_log.h"
#include "nt_linux_smart_player_sdk.h"
#include "nt_player_sdk_wrapper.h"....const char* players_url_[]
{"rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream","rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream","rtsp://admin:admin123456@192.168.0.121:554/cam/realmonitor?channel=1&subtype=0","rtsp://admin:admin123456@192.168.0.121:554/cam/realmonitor?channel=1&subtype=0",
};int main(int argc, char *argv[])
{XInitThreads(); // X支持多线程, 必须调用NT_SDKLogInit();// SDK初始化SmartPlayerSDKAPI player_api;if (!NT_PlayerSDKInit(player_api)){fprintf(stderr, "SDK init failed.\n");return 0;}auto display = XOpenDisplay(nullptr);if (!display){fprintf(stderr, "Cannot connect to X server\n");player_api.UnInit();return 0;}auto screen = DefaultScreen(display);auto root = XRootWindow(display, screen);XWindowAttributes root_win_att;if (!XGetWindowAttributes(display, root, &root_win_att)){fprintf(stderr, "Get Root window attri failed\n");player_api.UnInit();XCloseDisplay(display);return 0;}if (root_win_att.width < 100 || root_win_att.height < 100){fprintf(stderr, "Root window size error.\n");player_api.UnInit();XCloseDisplay(display);return 0;}fprintf(stdout, "Root Window Size:%d*%d\n", root_win_att.width, root_win_att.height);int main_w = root_win_att.width / 2, main_h = root_win_att.height/2;auto black_pixel = BlackPixel(display, screen);auto white_pixel = WhitePixel(display, screen);auto main_wid = XCreateSimpleWindow(display, root, 0, 0, main_w, main_h, 0, white_pixel, black_pixel);if (!main_wid){player_api.UnInit();XCloseDisplay(display);fprintf(stderr, "Cannot create main windows\n");return 0;}XSelectInput(display, main_wid, StructureNotifyMask | KeyPressMask);XMapWindow(display, main_wid);XStoreName(display, main_wid, win_base_title);std::vector<std::shared_ptr<NT_PlayerSDKWrapper> > players;for (auto url: players_url_){auto i = std::make_shared<NT_PlayerSDKWrapper>(&player_api);i->SetDisplay(display);i->SetScreen(screen);i->SetURL(url);players.push_back(i);if ( players.size() > 3 )break;}auto border_w = 2;std::vector<NT_LayoutRect> layout_rects;SubWindowsLayout(main_w, main_h, border_w, static_cast<int>(players.size()), layout_rects);for (auto i = 0; i < static_cast<int>(players.size()); ++i){assert(players[i]);players[i]->SetWindow(CreateSubWindow(display, screen, main_wid, layout_rects[i], border_w));}for (const auto& i : players){assert(i);if (i->GetWindow())XMapWindow(display, i->GetWindow());}for (auto i = 0; i < static_cast<int>(players.size()); ++i){assert(players[i]);// 第一路不静音, 其他全部静音players[i]->Start(0, i!=0, 1, false);//players[i]->Start(0, false, 1, false);}while (true){while (MY_X11_Pending(display, 10)){XEvent xev;memset(&xev, 0, sizeof(xev));XNextEvent(display, &xev);if (xev.type == ConfigureNotify){if (xev.xconfigure.window == main_wid){if (xev.xconfigure.width != main_w || xev.xconfigure.height != main_h){main_w = xev.xconfigure.width;main_h = xev.xconfigure.height;SubWindowsLayout(main_w, main_h, border_w, static_cast<int>(players.size()), layout_rects);for (auto i = 0; i < static_cast<int>(players.size()); ++i){if (players[i]->GetWindow()){XMoveResizeWindow(display, players[i]->GetWindow(), layout_rects[i].x_, layout_rects[i].y_, layout_rects[i].w_, layout_rects[i].h_);}}}}else{for (const auto& i: players){assert(i);if (i->GetWindow() && i->GetWindow() == xev.xconfigure.window){i->OnWindowSize(xev.xconfigure.width, xev.xconfigure.height);}}}}else if (xev.type == KeyPress){if (xev.xkey.keycode == XKeysymToKeycode(display, XK_Escape)){fprintf(stdout, "ESC Key Press\n");for (const auto& i : players){i->Stop();if (i->GetWindow()){XDestroyWindow(display, i->GetWindow());i->SetWindow(None);}}players.clear();XDestroyWindow(display, main_wid);XCloseDisplay(display);player_api.UnInit();fprintf(stdout, "Close Players....\n");return 0;}}}}
}

开始播放、停止播放封装实现

bool NT_PlayerSDKWrapper::Start(int buffer, bool is_mute, int render_scale_mode, bool is_only_dec_key_frame)
{if (is_playing_)return false;if (url_.empty())return false;if (!OpenHandle(url_, buffer))return false;assert(handle_ && handle_->Handle());// 音频参数player_api_->SetMute(handle_->Handle(), is_mute ? 1 : 0);player_api_->SetIsOutputAudioDevice(handle_->Handle(), 1);player_api_->SetAudioOutputLayer(handle_->Handle(), 0); // 使用pluse 或者 alsa播放, 两个可以选择一个// 视频参数player_api_->SetVideoSizeCallBack(handle_->Handle(), this, &NT_Player_SDK_WRAPPER_OnVideoSizeHandle);//player_api_->SetXDisplayName(handle_->Handle(), NULL);player_api_->SetXScreenNumber(handle_->Handle(),screen_);player_api_->SetRenderXWindow(handle_->Handle(), window_);player_api_->SetRenderScaleMode(handle_->Handle(), render_scale_mode);player_api_->SetRenderTextureScaleFilterMode(handle_->Handle(), 3);player_api_->SetOnlyDecodeVideoKeyFrame(handle_->Handle(), is_only_dec_key_frame ? 1 : 0);auto ret = player_api_->StartPlay(handle_->Handle());if (NT_ERC_OK != ret){ResetHandle();return false;}is_playing_ = true;return true;
}void NT_PlayerSDKWrapper::Stop()
{if (!is_playing_)return;assert(handle_);player_api_->StopPlay(handle_->Handle());video_width_ = 0;video_height_ = 0;ResetHandle();is_playing_ = false;
}

Event回调

bool NT_PlayerSDKWrapper::AttachHandle(const std::shared_ptr<NT_SDK_HandleWrapper>& handle)
{if (is_playing_)return false;handle_ = handle;if (handle_){handle_->AddEventHandler(shared_from_this());}return true;
}

视频分辨率回调

extern "C" NT_VOID NT_CALLBACK NT_Player_SDK_WRAPPER_OnVideoSizeHandle(NT_HANDLE handle, NT_PVOID user_data,NT_INT32 width, NT_INT32 height)
{auto sdk_wrapper = reinterpret_cast<NT_PlayerSDKWrapper*>(user_data);if (nullptr == sdk_wrapper)return;sdk_wrapper->VideoSizeHandle(handle, width, height);
}

实时快照回调

extern "C" NT_VOID NT_CALLBACK NT_Player_SDK_WRAPPER_OnCaptureImageCallBack(NT_HANDLE handle, NT_PVOID user_data, NT_UINT32 result, NT_PCSTR file_name)
{auto sdk_wrapper = reinterpret_cast<NT_PlayerSDKWrapper*>(user_data);if (nullptr == sdk_wrapper)return;sdk_wrapper->CaptureImageHandle(handle, result, file_name);
}

总结

arm64架构的国产操作系统|Linux下的RTMP、RTSP直播播放,延迟依然毫秒级,随着国产操作系统在传统行业的推进,越来越多的场景需要高稳定性高延迟低的RTMP|RTSP播放器,本文抛砖引玉,感兴趣的开发者可以跟我单独探讨。

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

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

相关文章

C++ 红黑树

目录 1.红黑树的概念 2.红黑树的性质 3.红黑树节点的定义 4.红黑树的插入操作 5.数据测试 1.红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个…

C++基础与深度解析 | 泛型算法 | bind | Lambda表达式

文章目录 一、泛型算法1.泛型算法的分类2.迭代器分类 二、bind与lambda表达式1.bind2.lambda表达式 三、泛型算法的改进--ranges(c20) 一、泛型算法 C中的泛型算法是标准模板库&#xff08;STL&#xff09;的一部分&#xff08;这里重点讨论 C 标准库中定义的算法&#xff0c;而…

【vue-cli搭建vue项目的过程2.x】

vue-cli搭建vue项目 vue-cli搭建vue项目安装node安装vue-cli脚手架并创建项目安装 Ant Design Vue或element-ui(笔者使用Ant-design-vue组件&#xff0c;并全局引入)开发安装三方库包1、Package.json文件---引入如下package.json文件执行npm i或npm install命令即可下载如下依赖…

数据结构~~链式二叉树

目录 一、基本概念 链式存储概念 二、链式二叉树的结构 链式二叉树结构 构建链式二叉树 二叉树的遍历 二叉树节点和高度等 二叉树销毁 三、链式二叉树的练习 相同的树 对称二叉树 另外一颗子树 二叉树前序遍历 二叉树遍历 四、完整代码 Tree.h Tree.c 五、总结 一…

Linux服务升级:Predixy 升级代理 Redis-cluster 集群

目录 一、实验 1.环境 2. 启动Redis服务 3.Predixy 升级代理 Redis-cluster 集群 二、问题 1. Predixy进行set操作报错 2.如何创建脚本启动predixy 3.Redis代理对比 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统版本节点软件IP备注CentOS7.9Redis…

Springboot开发 -- Postman 调试类型详解

引言 在 Spring Boot 应用开发过程中&#xff0c;接口测试是必不可少的一环。Postman 作为一款强大的 API 开发和测试工具&#xff0c;可以帮助开发者轻松构建、测试和管理 HTTP 请求。本文将为大家介绍如何在 Spring Boot 开发中使用 Postman 进行接口测试。 一、准备工作 安…

C/C++|malloc分配内存详解

看本节前&#xff0c;希望读者有linux内存分布的基本概念&#xff0c;可以阅读这篇文章&#xff1a; 进程虚拟地址空间和函数调用栈 在本节中希望读者可以一口气阅读完所有内容。 本博客内容全部来自小林coding&#xff1a;malloc 是如何分配内存的&#xff1f; 这里仅为笔记记…

Python-图片旋转360,保存对应图片

#Author &#xff1a;susocool #Creattime:2024/5/25 #FileName:turn360 #Description: 会旋转指定的图像文件360度&#xff0c;并将每个旋转后的图像保存到指定目录&#xff0c;文件名以旋转角度命名。 from PIL import Imagedef rotate_and_save(image_path, output_dir) :# …

Linux/Ubuntu 中安装 ZeroTier,实现内网穿透,2分钟搞定

相信很多人都有远程连接家中设备的需求&#xff0c;如远程连接家中的NAS、Windows等服务&#xff0c;所以会涉及到一个内网穿透工具的使用&#xff0c;如果没有公网IP的情况下&#xff0c;推荐大家使用ZeroTier&#xff0c;这是一款强大的内网穿透工具。 mac和windows版的操作…

Nginx-狂神说

Nginx概述 公司产品出现瓶颈&#xff1f; 我们公司项目刚刚上线的时候&#xff0c;并发量小&#xff0c;用户使用的少&#xff0c;所以在低并发的情况下&#xff0c;一个jar包启动应用就够了&#xff0c;然后内部tomcat返回内容给用户。 但是慢慢的&#xff0c;使用我们平台…

HTTP 各版本差异

http1.0 它的特点是每次请球和响应完毕后都会销毁TCP 连接。同时规走前一个响应完成后才发送下一个请求。这样做有两个问题&#xff1a; 无法复用连接了。 每次请求都要创建新的TCP连接&#xff0c;完成三次握手和四次挥手。网络利用率低 队头阻塞 如果前一个请求被某种原因阻…

K8S认证|CKA题库+答案| 13. sidecar 代理容器日志

目录 13、使用 sidecar 代理容器日志 CKA v1.29.0模拟系统免费下载试用&#xff1a; 题目&#xff1a; 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、生成yaml文件 3&#xff09;、官网找模板 4&#xff09;、编辑yaml文件 5&#xff09;、应用yaml…

车载电子电器架构 —— 智能座舱技术

车载电子电器架构 —— 智能座舱技术 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的…

qt multiple definition of 报错解决

qt编译报了很多错&#xff0c; multiple definition of xxx 原来一维设计文件ui 的问题 后来发现是pro中头文件和cpp文件重写了&#xff0c;导致重复编译报的错 解决方法&#xff1a;把重复的头文件和cpp文件删了就可以了。

如何解决0.1+0.2!=0.3的问题

var x 0.1; var y 0.2; var z x y // z 的结果为 0.30000000000000004 if (z 0.3) // 返回 false 可以用整数的乘除法来解决 var z (x * 10 y * 10) / 10; // z 的结果为 0.3

GEO数据挖掘-GEO背景知识+表达芯片分析思路

From生物技能树 GEO数据挖掘第一节 &#xff08;pipeline&#xff09; 文章目录 1.图表分析2.GEO背景介绍及分析思路3.代码分析流程4.复杂数据分析理论知识1.数据从哪里来2.有什么类型的数据可挖掘3.如何筛选基因&#xff08;分析方法&#xff09;在这里插入图片描述 图表介绍1…

Jenkins + github 自动化部署配置

1 Jenkins安装 AWS EC2安装Jenkins&#xff1a;AWS EC2 JDK11 Jenkins-CSDN博客 AWS EC2上Docker安装Jenkins&#xff1a;https://blog.csdn.net/hhujjj2005/article/details/139078402 2 登录jenkins http://192.168.1.128:8080/ $ docker exec -it d1851d9e3386 /bin/ba…

Multi-objective reinforcement learning approach for trip recommendation

Multi-objective reinforcement learning approach for trip recommendation A B S T R A C T 行程推荐是一项智能服务&#xff0c;为游客在陌生的城市提供个性化的行程规划。 它旨在构建一系列有序的 POI&#xff0c;在时间和空间限制下最大化用户的旅行体验。 将候选 POI 添…

【Shell】sed编辑器实例

sed是用来解析和转换文本的工具&#xff0c;它使用简单&#xff0c;是简洁的程序设计语言。 sed编辑器 &#xff08;一&#xff09; sed编辑器基础1. 简介2. sed的模式空间 &#xff08;二&#xff09;基本的sed编辑命令&#xff08;三&#xff09;sed命令实例1. 向文件中添加或…

MFC GDI 绘图模式、映射模式、画笔、笔、字体

一 GDI 绘图模式&#xff08;RoP2 Mode&#xff09; 在使用VC MFC进行图形程序编程时&#xff0c;常会用到GDI绘图指令&#xff0c;而要做到绘图时有橡皮筋动态效果&#xff0c;就需设置GDI绘图模式。GDI绘图模式有多种&#xff0c;如下&#xff1a; 常用R2_NOT模式来实…