基于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.pswp.cn/bicheng/15977.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/15977.shtml
英文地址,請注明出處:http://en.pswp.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模式來實…