基于RTMP实现Linux|麒麟操作系统下屏幕|系统声音采集推送

简介: Windows操作系统自问世以来,以其简单易用的图形化界面操作受到大众追捧,为计算机的普及、科技的发展做出了不可磨灭的功绩,也慢慢的成为人们最依赖的操作系统。在中国,90%以上的办公环境都是Windows,学校和各种培训班的培训内容也都是Windows,Windows操作系统已经渗入到各行各业,人们已经习惯了Windows的界面和操作习惯,IT计算机和Windows已经被习以为常的画上了等号。

背景

Windows操作系统自问世以来,以其简单易用的图形化界面操作受到大众追捧,为计算机的普及、科技的发展做出了不可磨灭的功绩,也慢慢的成为人们最依赖的操作系统。在中国,90%以上的办公环境都是Windows,学校和各种培训班的培训内容也都是Windows,Windows操作系统已经渗入到各行各业,人们已经习惯了Windows的界面和操作习惯,IT计算机和Windows已经被习以为常的画上了等号。


但是,我们使用的软件真的安全吗?黑屏事件和棱镜门事件让很多乐观看待或尚未意识到信息安全问题的人们警醒,我们所使用的国外软件并不是安全的,我们的数据完全掌握在别人手中。随着信息安全上升到了国家战略的高度,推行自主可控的国产操作系统势在必行。国产操作系统作为自主可控的基础,市场迅速升温,受到了社会各界的高度关注。


我们有别的选择吗?


其实基于开源软件Linux二次开发的操作系统,近年来的发展趋势非常迅猛。Linux已经有20年历史,尤其近十年经过突飞猛进的发展,Linux桌面操作系统已经远远摆脱了“具备与主流桌面操作系统的可比性”阶段,基于拥有众多优秀的开源应用软件的基础,在软件多样性、硬件兼容性、用户体验等各方面做了大量的改进,现在已经可以满足日常办公的需求。在欧美,我们不时听到一些政府部门将采用Linux桌面办公:慕尼黑市政府用十年的时间,成功的“赶走”了微软;伯明翰市政府、法国国会、瑞士、挪威和南非政府部门也都采用了Linux桌面办公。

国产操作系统|Linux下RTMP同屏推送

在发布国产操作系统|Linux平台的RTMP直播推送SDK之前,大牛直播SDK(官方)的RTMP推送模块已稳定运行在Windows、Android和iOS平台几年了。


相对Windows、Android和iOS平台,Linux在桌面采集等方面,资料非常少,数据采集可以采用调用XLib相关接口实现,本Demo实现的是Linux上实现桌面和系统声音采集,然后使用RTMP协议推出去的一个SDK. 集成调用非常简单。

相关实现

int main(int argc, char *argv[])
{
  signal(SIGINT, &OnSigIntHandler);
  //printf("sizeof(NT_SmartPublisherSDKAPI)=%d\n", sizeof(NT_SmartPublisherSDKAPI));
  LogInit();
  NT_SmartPublisherSDKAPI push_api;
  if (!PushSDKInit(push_api))
  {
    return 0;
  }
  auto push_handle = StartPush(&push_api, "rtmp://192.168.0.154:1935/live/test1", 30);
  if (!push_handle)
  {
    fprintf(stderr, "start push failed.\n");
    push_api.UnInit();
    return 0;
  }
  while (!g_is_exit)
  {
    sleep(2);
  }
  fprintf(stdout, "Skip run loop, is_exit:%d\n", g_is_exit);
  push_api.StopPublisher(push_handle);
  push_api.Close(push_handle);
  push_handle = nullptr;
  push_api.UnInit();
  fprintf(stdout, "SDK UnInit..\n");
  return 0;
}

相关初始化

  void OnSigIntHandler(int sig)
  {
    if (SIGINT == sig)
    {
      g_is_exit = true;
    }
  }
  void LogInit()
  {
    SmartLogAPI log_api;
    memset(&log_api, 0, sizeof(log_api));
    GetSmartLogAPI(&log_api);
    log_api.SetLevel(SL_INFO_LEVEL);
    log_api.SetPath((NT_PVOID)"./");
  }
  bool PushSDKInit(NT_SmartPublisherSDKAPI& push_api)
  {
    memset(&push_api, 0, sizeof(push_api));
    NT_GetSmartPublisherSDKAPI(&push_api);
    auto ret = push_api.Init(0, nullptr);
    if (NT_ERC_OK != ret)
    {
      fprintf(stderr, "push_api.Init failed!\n");
      return false;
    }
    else
    {
      fprintf(stdout, "push_api.Init ok!\n");
    }
    return true;
  }


推送接口封装

  NT_HANDLE StartPush(NT_SmartPublisherSDKAPI* push_api, const std::string& rtmp_url, int dst_fps)
  {
    NT_INT32 pulse_device_number = 0;
    if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(2, &pulse_device_number))
    {
      fprintf(stdout, "Pulse device num:%d\n", pulse_device_number);
      char device_name[512];
      for (auto i = 0; i < pulse_device_number; ++i)
      {
        if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(2, i, device_name, 512))
        {
          fprintf(stdout, "index:%d name:%s\n", i, device_name);
        }
      }
    }
    NT_INT32 alsa_device_number = 0;
    if (pulse_device_number < 1)
    {
      if (NT_ERC_OK == push_api->GetAuidoInputDeviceNumber(1, &alsa_device_number))
      {
        fprintf(stdout, "Alsa device num:%d\n", alsa_device_number);
        char device_name[512];
        for (auto i = 0; i < alsa_device_number; ++i)
        {
          if (NT_ERC_OK == push_api->GetAuidoInputDeviceName(1, i, device_name, 512))
          {
            fprintf(stdout, "index:%d name:%s\n", i, device_name);
          }
        }
      }
    }
    NT_INT32 capture_speaker_flag = 0;
    if ( NT_ERC_OK == push_api->IsCanCaptureSpeaker(2, &capture_speaker_flag) )
    {
      if (capture_speaker_flag)
        fprintf(stdout, "Support speaker capture\n");
      else
        fprintf(stdout, "UnSupport speaker capture\n");
    }
    NT_INT32 is_support_window_capture = 0;
    if (NT_ERC_OK == push_api->IsCaptureWindowSupported(NULL, &is_support_window_capture))
    {
      if (is_support_window_capture)
        fprintf(stdout, "Support window capture\n");
      else
        fprintf(stdout, "UnSupport window capture\n");
    }
    NT_HANDLE push_handle = nullptr;
    // if (NT_ERC_OK != push_api->Open(&push_handle, NT_PB_E_VIDEO_OPTION_LAYER, NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER, 0, NULL))
    if (NT_ERC_OK != push_api->Open(&push_handle, NT_PB_E_VIDEO_OPTION_SCREEN, NT_PB_E_AUDIO_OPTION_CAPTURE_SPEAKER, 0, NULL))
    {
      return nullptr;
    }
    //push_api->SetXDisplayName(push_handle, ":0");
    //push_api->SetXDisplayName(push_handle, NULL);
    // 视频层配置方式
    //std::vector<std::shared_ptr<nt_pb_sdk::layer_conf_wrapper_base> > layer_confs;
    //auto index = 0;
     第0层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑
    //auto rgba_layer_c0 = std::make_shared<nt_pb_sdk::RGBARectangleLayerConfigWrapper>(index++, true, 0, 0, 1280, 720);
    //rgba_layer_c0->conf_.red_ = 0;
    //rgba_layer_c0->conf_.green_ = 0;
    //rgba_layer_c0->conf_.blue_ = 0;
    //rgba_layer_c0->conf_.alpha_ = 255;
    //layer_confs.push_back(rgba_layer_c0);
     第一层为桌面层
    //auto screen_layer_c1 = std::make_shared<nt_pb_sdk::ScreenLayerConfigWrapper>(index++, true, 0, 0, 1280, 720);
    //
    //screen_layer_c1->conf_.scale_filter_mode_ = 3;
    //layer_confs.push_back(screen_layer_c1);
    //std::vector<const NT_PB_LayerBaseConfig* > layer_base_confs;
    //for (const auto& i : layer_confs)
    //{
    //  layer_base_confs.push_back(i->getBase());
    //}
    //if (NT_ERC_OK != push_api->SetLayersConfig(push_handle, 0, layer_base_confs.data(),
    //  layer_base_confs.size(), 0, nullptr))
    //{
    //  push_api->Close(push_handle);
    //  push_handle = nullptr;
    //  return nullptr;
    //}
    // push_api->SetScreenClip(push_handle, 0, 0, 1280, 720);
    push_api->SetFrameRate(push_handle, dst_fps); // 帧率设置
    push_api->SetVideoBitRate(push_handle, 2000);  // 平均码率2000kbps
    push_api->SetVideoQualityV2(push_handle, 26); 
    push_api->SetVideoMaxBitRate(push_handle, 4000); // 最大码率4000kbps
    push_api->SetVideoKeyFrameInterval(push_handle, dst_fps*2); // 关键帧间隔
    push_api->SetVideoEncoderProfile(push_handle, 3); // h264 baseline
    push_api->SetVideoEncoderSpeed(push_handle, 3); // 编码速度设置到3
    if (pulse_device_number > 0)
    {
      push_api->SetAudioInputLayer(push_handle, 2);
      push_api->SetAuidoInputDeviceId(push_handle, 0);
    }
    else if (alsa_device_number > 0)
    {
      push_api->SetAudioInputLayer(push_handle, 1);
      push_api->SetAuidoInputDeviceId(push_handle, 0);
    }
    // 音频配置
    push_api->SetPublisherAudioCodecType(push_handle, 1);
    //push_api->SetMute(push_handle, 1);
    if ( NT_ERC_OK != push_api->SetURL(push_handle, rtmp_url.c_str(), NULL) )
    {
      push_api->Close(push_handle);
      push_handle = nullptr;
      return nullptr;
    }
    if ( NT_ERC_OK != push_api->StartPublisher(push_handle, NULL) )
    {
      push_api->Close(push_handle);
      push_handle = nullptr;
      return nullptr;
    }
    return push_handle;
  }


相关界面

20210722122604812.png

总结

实际测试下来,以RTMP推送和RTMP播放为例,整体测试时延都在毫秒级,可满足像内网无纸化、教育同屏等场景需求。


Linux的RTMP推送接口,和Windows平台的相差无几,通用接口四个平台几乎一致,不存在集成难度。


国产操作系统替代windows,也许并不像你想象的那么遥远,使用习惯上也并不像想象中那么难,相信在不久的将来,国产操作系统会真正被市场广泛使用。


国产操作系统下的应用生态的创建,需要国人一点点建立。

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
相关文章
|
4天前
|
Ubuntu Linux 网络安全
从头安装Arch Linux系统
本文记录了作者安装Arch Linux系统的过程,包括安装成果展示和遇到的疑难点及其解决方法,如硬盘不足、下载失败、设置时区、安装微码和配置无密码登录等。
从头安装Arch Linux系统
|
1天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
3天前
|
移动开发 Android开发 数据安全/隐私保护
移动应用与系统的技术演进:从开发到操作系统的全景解析随着智能手机和平板电脑的普及,移动应用(App)已成为人们日常生活中不可或缺的一部分。无论是社交、娱乐、购物还是办公,移动应用都扮演着重要的角色。而支撑这些应用运行的,正是功能强大且复杂的移动操作系统。本文将深入探讨移动应用的开发过程及其背后的操作系统机制,揭示这一领域的技术演进。
本文旨在提供关于移动应用与系统技术的全面概述,涵盖移动应用的开发生命周期、主要移动操作系统的特点以及它们之间的竞争关系。我们将探讨如何高效地开发移动应用,并分析iOS和Android两大主流操作系统的技术优势与局限。同时,本文还将讨论跨平台解决方案的兴起及其对移动开发领域的影响。通过这篇技术性文章,读者将获得对移动应用开发及操作系统深层理解的钥匙。
|
1天前
|
Ubuntu Linux Shell
Linux系统密码忘记
【10月更文挑战第2天】在Linux系统中,若忘记密码,可以通过单用户模式或使用Live CD/USB来重置。对于Ubuntu系统,可通过GRUB引导菜单进入单用户模式,利用命令行重置密码;或使用Live CD/USB启动并挂载硬盘分区后修改密码文件。CentOS系统同样支持单用户模式重置密码,也可借助安装介质进入救援模式,挂载文件系统后进行密码重置。这些方法均能在忘记密码的情况下帮助恢复系统访问。
|
3天前
|
人工智能 安全 数据安全/隐私保护
移动应用与系统:构建现代数字生态的双引擎在数字化浪潮席卷全球的今天,移动应用与系统作为连接用户与数字世界的重要桥梁,正发挥着越来越重要的作用。它们不仅改变了人们的生活方式,也推动了各行各业的创新与发展。本文将深入探讨移动应用开发的最新趋势、移动操作系统的演进历程以及两者如何共同塑造我们的未来。
随着智能手机的普及和移动互联网的快速发展,移动应用已成为人们日常生活中不可或缺的一部分。从社交媒体到移动支付,从在线教育到远程办公,移动应用无处不在,极大地丰富了我们的生活体验。与此同时,移动操作系统也在不断进化,为应用提供了更加稳定、高效的运行环境。本文旨在分析当前移动应用开发的热点技术、探讨移动操作系统的未来发展方向,并展望这两者如何相互促进,共同推动数字经济的繁荣。
|
2天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
3天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
4天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
3天前
|
Linux Python Perl
Linux命令删除文件里的字符串
Linux命令删除文件里的字符串
15 7
|
4天前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
下一篇
无影云桌面