• 如何在Unity下采集音视频实现轻量级RTSP服务(类似于IPC)


    好多开发者在做虚拟仿真、VR教育等场景的时候,遇到个问题,想把头显里面的画面在内网环境下低延迟的同步出来,又不想单独部署流媒体服务器。为此,我们在Unity下,添加了轻量级RTSP服务模块,通过头显端启动个轻量级RTSP服务,把采集到的音视频数据,通过对外提供RTSP拉流URL的形式,供内网其他终端调用,废话不多说,先上图看效果:

     上图展示的是,Android的Unity下Camera场景获取到texture数据编码后,注入RTSP服务和RTMP推送模块。二者可以单独使用,也可同时使用,相互不影响。其中轻量级RTSP服务,可实时查看链接的RTSP会话数。

    由于我们原生Android平台轻量级RTSP服务已经有多年积累,本次只是把相关的接口,同步过来。

    首先来看RTSP Server相关的接口设计:

    1. /*
    2. * SmartPublisherAndroidMono.cs
    3. *
    4. * Github: https://github.com/daniulive/SmarterStreaming
    5. */
    6. /*+++++++++++++++SmartRTSPServerSDK+++++++++++++++*/
    7. ///
    8. /// Init rtsp server(和UnInitRtspServer配对使用,即便是启动多个RTSP服务,也只需调用一次InitRtspServer,请确保在OpenRtspServer之前调用)
    9. ///
    10. public int NT_PB_U3D_InitRtspServer()
    11. {
    12. return pusher_obj_.Call<int>("InitRtspServer");
    13. }
    14. ///
    15. /// 创建一个rtsp server
    16. ///
    17. public long NT_PB_U3D_OpenRtspServer(int reserve)
    18. {
    19. return pusher_obj_.Call<long>("OpenRtspServer", reserve);
    20. }
    21. ///
    22. /// 设置rtsp server 监听端口, 在StartRtspServer之前必须要设置端口
    23. /// @param rtsp_server_handle: rtsp server 句柄
    24. /// @param port: 端口号,可以设置为554,或者是1024到65535之间,其他值返回失败
    25. ///
    26. public int NT_PB_U3D_SetRtspServerPort(long rtsp_server_handle, int port)
    27. {
    28. return pusher_obj_.Call<int>("SetRtspServerPort", rtsp_server_handle, port);
    29. }
    30. ///
    31. /// 设置rtsp server 鉴权用户名和密码, 这个可以不设置,只有需要鉴权的再设置
    32. /// @param rtsp_server_handle: rtsp server 句柄
    33. /// @param user_name: 用户名(必须是英文), password:密码(必须是英文)
    34. ///
    35. public int NT_PB_U3D_SetRtspServerUserNamePassword(long rtsp_server_handle, String user_name, String password)
    36. {
    37. return pusher_obj_.Call<int>("SetRtspServerUserNamePassword", rtsp_server_handle, user_name, password);
    38. }
    39. ///
    40. /// 设置rtsp server 组播, 如果server设置成组播就不能单播,组播和单播只能选一个, 一般来说单播网络设备支持的好,wifi组播很多路由器不支持
    41. /// @param rtsp_server_handle: rtsp server 句柄
    42. /// @param is_multicast: 是否组播, 1为组播, 0为单播, 其他值接口返回错误, 默认是单播
    43. ///
    44. public int NT_PB_U3D_SetRtspServerMulticast(long rtsp_server_handle, int is_multicast)
    45. {
    46. return pusher_obj_.Call<int>("SetRtspServerMulticast", rtsp_server_handle, is_multicast);
    47. }
    48. ///
    49. /// 设置rtsp server 组播组播地址
    50. /// @param rtsp_server_handle: rtsp server 句柄
    51. /// 如果设置的不是组播地址, 将返回错误
    52. /// 组播地址范围说明: [224.0.0.0, 224.0.0.255] 为组播预留地址, 不能设置. 可设置范围为[224.0.1.0, 239.255.255.255], 其中SSM地址范围为[232.0.0.0, 232.255.255.255]
    53. ///
    54. public int NT_PB_U3D_SetRtspServerMulticastAddress(long rtsp_server_handle, String multicast_address)
    55. {
    56. return pusher_obj_.Call<int>("SetRtspServerMulticastAddress", rtsp_server_handle, multicast_address);
    57. }
    58. ///
    59. /// 获取rtsp server当前的客户会话数, 这个接口必须在StartRtspServer之后再调用
    60. /// @param rtsp_server_handle: rtsp server 句柄
    61. /// @return {当前rtsp server会话数}
    62. ///
    63. public int NT_PB_U3D_GetRtspServerClientSessionNumbers(long rtsp_server_handle)
    64. {
    65. return pusher_obj_.Call<int>("GetRtspServerClientSessionNumbers", rtsp_server_handle);
    66. }
    67. ///
    68. /// 启动rtsp server
    69. /// @param rtsp_server_handle: rtsp server 句柄
    70. /// @param reserve: 保留参数传0
    71. ///
    72. public int NT_PB_U3D_StartRtspServer(long rtsp_server_handle, int reserve)
    73. {
    74. return pusher_obj_.Call<int>("StartRtspServer", rtsp_server_handle, reserve);
    75. }
    76. ///
    77. /// 停止rtsp server
    78. /// @param rtsp_server_handle: rtsp server 句柄
    79. ///
    80. public int NT_PB_U3D_StopRtspServer(long rtsp_server_handle)
    81. {
    82. return pusher_obj_.Call<int>("StopRtspServer", rtsp_server_handle);
    83. }
    84. ///
    85. /// 关闭rtsp server
    86. /// @param rtsp_server_handle: rtsp server 句柄
    87. /// NOTE: 调用这个接口之后rtsp_server_handle失效,
    88. ///
    89. public int NT_PB_U3D_CloseRtspServer(long rtsp_server_handle)
    90. {
    91. return pusher_obj_.Call<int>("CloseRtspServer", rtsp_server_handle);
    92. }
    93. ///
    94. /// UnInit rtsp server(和InitRtspServer配对使用,即便是启动多个RTSP服务,也只需调用一次UnInitRtspServer)
    95. ///
    96. public int NT_PB_U3D_UnInitRtspServer()
    97. {
    98. return pusher_obj_.Call<int>("UnInitRtspServer");
    99. }
    100. /*---------------SmartRTSPServerSDK---------------*/

    其次是,用于publisher实例操作的接口,把publisher实例和rtsp实例串起来:

    1. /*+++++++++++++++SmartRTSPServerSDK供Publisher调用的接口+++++++++++++++*/
    2. ///
    3. /// 设置rtsp的流名称
    4. /// @param handle: 推送实例句柄
    5. /// @param stream_name: 流程名称,不能为空字符串,必须是英文
    6. /// 这个作用是: 比如rtsp的url是:rtsp://192.168.0.111/test, test就是设置下去的stream_name
    7. ///
    8. public int NT_PB_U3D_SetRtspStreamName(long handle, String stream_name)
    9. {
    10. return pusher_obj_.Call<int>("SetRtspStreamName", handle, stream_name);
    11. }
    12. ///
    13. /// 给要发布的rtsp流设置rtsp server, 一个流可以发布到多个rtsp server上,rtsp server的创建启动请参考OpenRtspServer和StartRtspServer接口
    14. /// @param handle: 推送实例句柄
    15. /// @param rtsp_server_handle:rtsp server句柄
    16. /// @param reserve:保留参数,传0
    17. ///
    18. public int NT_PB_U3D_AddRtspStreamServer(long handle, long rtsp_server_handle, int reserve)
    19. {
    20. return pusher_obj_.Call<int>("AddRtspStreamServer", handle, rtsp_server_handle, reserve);
    21. }
    22. ///
    23. /// 清除设置的rtsp server
    24. /// @param handle: 推送实例句柄
    25. ///
    26. public int NT_PB_U3D_ClearRtspStreamServer(long handle)
    27. {
    28. return pusher_obj_.Call<int>("ClearRtspStreamServer", handle);
    29. }
    30. ///
    31. /// 启动rtsp流
    32. /// @param handle: 推送实例句柄
    33. /// @param reserve: 保留参数,传0
    34. ///
    35. public int NT_PB_U3D_StartRtspStream(long handle, int reserve)
    36. {
    37. return pusher_obj_.Call<int>("StartRtspStream", handle, reserve);
    38. }
    39. ///
    40. /// 停止rtsp流
    41. /// @param handle: 推送实例句柄
    42. ///
    43. public int NT_PB_U3D_StopRtspStream(long handle)
    44. {
    45. return pusher_obj_.Call<int>("StopRtspStream", handle);
    46. }
    47. /*---------------SmartRTSPServerSDK供Publisher调用的接口---------------*/

    Unity调用demo如下:

    启动、停止轻量级服务:

    1. private void OnRtspServiceBtnClicked()
    2. {
    3. if (is_rtsp_service_running_) {
    4. StopRtspService();
    5. btn_rtsp_service_.GetComponentInChildren().text = "启动RTSP服务";
    6. btn_rtsp_publisher_.GetComponent
    7. return;
    8. }
    9. rtsp_handle_ = NT_PB_U3D_OpenRtspServer(0);
    10. if (rtsp_handle_ == 0) {
    11. Debug.LogError("创建rtsp server实例失败! 请检查SDK有效性");
    12. } else {
    13. int port = 8554;
    14. if (NT_PB_U3D_SetRtspServerPort(rtsp_handle_, port) != 0) {
    15. NT_PB_U3D_CloseRtspServer(rtsp_handle_);
    16. rtsp_handle_ = 0;
    17. Debug.LogError("创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!");
    18. }
    19. if (NT_PB_U3D_StartRtspServer(rtsp_handle_, 0) == DANIULIVE_RETURN_OK) {
    20. is_rtsp_service_running_ = true;
    21. Debug.Log("启动rtsp server 成功!");
    22. } else {
    23. NT_PB_U3D_CloseRtspServer(rtsp_handle_);
    24. rtsp_handle_ = 0;
    25. Debug.LogError("启动rtsp server失败! 请检查设置的端口是否被占用!");
    26. }
    27. btn_rtsp_service_.GetComponentInChildren().text = "停止RTSP服务";
    28. btn_rtsp_publisher_.GetComponent
    29. }
    30. }

    服务启动后,可以发布或停止RTSP流:

    1. private void OnRtspPublisherBtnClicked()
    2. {
    3. if (is_rtsp_publisher_running_)
    4. {
    5. StopRtspPublisher();
    6. if (!is_pushing_rtmp_)
    7. {
    8. StopCaptureAvData();
    9. if (coroutine_ != null) {
    10. StopCoroutine(coroutine_);
    11. coroutine_ = null;
    12. }
    13. }
    14. btn_rtsp_publisher_.GetComponentInChildren().text = "发布RTSP流";
    15. btn_get_rtsp_session_numbers_.GetComponentInChildren().text = "RTSP会话数";
    16. btn_get_rtsp_session_numbers_.GetComponent
    17. btn_rtsp_service_.GetComponent
    18. input_url_.GetComponentInChildren().text = "";
    19. }
    20. else
    21. {
    22. bool is_started = StartRtspPublisher();
    23. if(is_started)
    24. {
    25. btn_rtsp_publisher_.GetComponentInChildren().text = "停止RTSP流";
    26. btn_get_rtsp_session_numbers_.GetComponent
    27. btn_rtsp_service_.GetComponent
    28. if(!is_pushing_rtmp_)
    29. {
    30. StartCaptureAvData();
    31. coroutine_ = StartCoroutine(OnPostVideo());
    32. }
    33. }
    34. }
    35. }

    发布RTSP流:

    1. private bool StartRtspPublisher()
    2. {
    3. if (is_rtsp_publisher_running_)
    4. {
    5. Debug.Log("已推送..");
    6. return false;
    7. }
    8. if (!is_pushing_rtmp_)
    9. {
    10. InitAndSetConfig();
    11. }
    12. if (pusher_handle_ == 0) {
    13. Debug.LogError("Start rtsp publisher, pusher handle is null..");
    14. return false;
    15. }
    16. String rtsp_stream_name = "stream1";
    17. NT_PB_U3D_SetRtspStreamName(pusher_handle_, rtsp_stream_name);
    18. NT_PB_U3D_ClearRtspStreamServer(pusher_handle_);
    19. NT_PB_U3D_AddRtspStreamServer(pusher_handle_, rtsp_handle_, 0);
    20. int is_suc = NT_PB_U3D_StartRtspStream(pusher_handle_, 0);
    21. if (is_suc == DANIULIVE_RETURN_OK)
    22. {
    23. Debug.Log("StartRtspStream success..");
    24. is_rtsp_publisher_running_ = true;
    25. }
    26. else
    27. {
    28. Debug.LogError("StartRtspStream failed!");
    29. return false;
    30. }
    31. return true;
    32. }

    停止发布RTSP流:

    1. //停止发布RTSP流
    2. private void StopRtspPublisher() {
    3. if(!is_rtsp_publisher_running_)
    4. return;
    5. NT_PB_U3D_StopRtspStream(pusher_handle_);
    6. if(!is_pushing_rtmp_)
    7. {
    8. NT_PB_U3D_Close(pusher_handle_);
    9. pusher_handle_ = 0;
    10. NT_PB_U3D_UnInit();
    11. }
    12. is_rtsp_publisher_running_ = false;
    13. }

    发布RTSP流后,我们可以实时获取到链接的RTSP会话数:

    1. private void OnGetRtspSessionNumbersBtnClicked()
    2. {
    3. if (rtsp_handle_ != 0)
    4. {
    5. int session_numbers = NT_PB_U3D_GetRtspServerClientSessionNumbers(rtsp_handle_);
    6. Debug.Log("GetRtspSessionNumbers: " + session_numbers);
    7. btn_get_rtsp_session_numbers_.GetComponentInChildren().text = "RTSP会话数:" + session_numbers.ToString();
    8. }
    9. }

    轻量级RTSP服务,由于不需要单独部署流媒体服务器,在内网小并发场景下,使用起来非常方便,感兴趣的开发者可酌情参考。

  • 相关阅读:
    imx6ull内置温度传感器实践1:输出一个采样
    链表高阶面试题及二叉树的遍历【前、中、后、层】
    Vulnhub靶机网卡启动失败(Raise network interfaces)
    TeeChart 的使用从入门到精通
    中值滤波算法及例程
    【计算机视觉】数字图像处理基础知识题
    Unity中实现ScrollRect 滚动定位到视口内
    CSP-J1 CSP-S1 初赛模拟题试卷整理2022.08.24
    Redis主从复制
    百看不厌的85M²现代极简装饰设计。福州中宅装饰,福州装修
  • 原文地址:https://blog.csdn.net/renhui1112/article/details/126950138