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

简介: 这段内容讲述了国产操作系统背景下,大牛直播SDK针对国产操作系统与Linux平台发布的RTMP/RTSP直播播放SDK。此SDK支持arm64架构,基于X协议输出视频,采用PulseAudio和Alsa Lib处理音频,具备实时静音、快照、缓冲时间设定等功能,并支持H.265编码格式。此外,提供了示例代码展示如何实现多实例播放器的创建与管理,包括窗口布局调整、事件监听、视频分辨率变化和实时快照回调等关键功能。这一技术实现有助于提高直播服务的稳定性和响应速度,适应国产操作系统在各行业中的应用需求。

技术背景

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;
                }
            }
        }
    }
}

image.gif

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

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;
}

image.gif

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;
}

image.gif

视频分辨率回调

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);
}

image.gif

实时快照回调

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);
}

image.gif

总结

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

相关文章
|
存储 机器学习/深度学习 数据库
阿里云服务器X86/ARM/GPU/裸金属/超算五大架构技术特点、场景适配参考
在云计算技术飞速发展的当下,云计算已经渗透到各个行业,成为企业数字化转型的关键驱动力。选择合适的云服务器架构对于提升业务效率、降低成本至关重要。阿里云提供了多样化的云服务器架构选择,包括X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等。本文将深入解析这些架构的特点、优势及适用场景,以供大家了解和选择参考。
1821 61
|
资源调度 前端开发 算法
鸿蒙OS架构设计探秘:从分层设计到多端部署
本文深入探讨了鸿蒙OS的架构设计,从独特的“1+8+N”分层架构到模块化设计,再到智慧分发和多端部署能力。分层架构让系统更灵活,模块化设计通过Ability机制实现跨设备一致性,智慧分发优化资源调度,多端部署提升开发效率。作者结合实际代码示例,分享了开发中的实践经验,并指出生态建设是未来的关键挑战。作为国产操作系统的代表,鸿蒙的发展值得每一位开发者关注与支持。
|
人工智能 芯片 开发者
鸿蒙电脑的诞生是国产操作系统的破壁之战
鸿蒙电脑的诞生标志着国产操作系统的重大突破。在Windows和Mac OS主导的市场中,华为凭借“全栈自研+分布式架构+系统级AI”创新组合,推出搭载HarmonyOS 5的HUAWEI MateBook Fold与MateBook Pro,实现从底层内核到用户体验的完全自主可控。作为混沌初开的“鸿蒙”,不仅补齐了华为“1+8+N”生态拼图,更开启了中国科技自立自强的新篇章。尽管生态建设仍在起步阶段,但已为全球电脑操作系统市场带来新格局。开发者可通过掌握ArkTS语言、利用分布式能力、参与开源项目等方式,抓住这一历史性机遇。
817 30
鸿蒙电脑的诞生是国产操作系统的破壁之战
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
7357 77
|
Ubuntu 搜索推荐 Linux
详解Ubuntu的strings与grep命令:Linux开发的实用工具。
这就是Ubuntu中的strings和grep命令,透明且强大。我希望你喜欢这个神奇的世界,并能在你的Linux开发旅程上,通过它们找到你的方向。记住,你的电脑是你的舞台,在上面你可以做任何你想做的事,只要你敢于尝试。
721 32
|
消息中间件 数据可视化 Kafka
docker arm架构部署kafka要点
本内容介绍了基于 Docker 的容器化解决方案,包含以下部分: 1. **Docker 容器管理**:通过 Portainer 可视化管理工具实现对主节点和代理节点的统一管理。 2. **Kafka 可视化工具**:部署 Kafka-UI 以图形化方式监控和管理 Kafka 集群,支持动态配置功能, 3. **Kafka 安装与配置**:基于 Bitnami Kafka 镜像,提供完整的 Kafka 集群配置示例,涵盖 KRaft 模式、性能调优参数及数据持久化设置,适用于高可用生产环境。 以上方案适合 ARM64 架构,为用户提供了一站式的容器化管理和消息队列解决方案。
1396 10
|
达摩院 安全 Anolis
Anolis OS 23 架构支持家族新成员:Anolis OS 23.3 版本及 RISC-V 预览版发布
Anolis OS 23.3在保障基础功能持续演进、完善安全漏洞的修复的同时,实现了对 RISC-V 的初步支持。
|
存储 机器学习/深度学习 算法
阿里云X86/ARM/GPU/裸金属/超算等五大服务器架构技术特点、场景适配与选型策略
在我们选购阿里云服务器的时候,云服务器架构有X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、高性能计算可选,有的用户并不清楚他们之间有何区别。本文将深入解析这些架构的特点、优势及适用场景,帮助用户更好地根据实际需求做出选择。
|
Cloud Native 安全 Linux
龙蜥操作系统:CentOS 谢幕之后,国产云原生系统的崛起之路
龙蜥操作系统(Anolis OS)是 CentOS 停止维护后,由阿里云等企业联合发起的开源项目。它以双内核架构和全栈优化为核心,提供无缝替代 CentOS 的方案,兼容主流生态并针对云计算场景深度优化。其技术亮点包括 RHCK 和 ANCK 双内核、性能优化、全栈安全及国密算法支持。龙蜥适用于云原生基础设施、企业级应用部署及开发环境,社区已吸引 200 多家单位参与。未来规划涵盖 AI 框架优化、RISC-V 架构适配及桌面环境构建,正重新定义云时代的操作系统边界。
5132 0

热门文章

最新文章