• Android平台轻量级RTSP服务模块如何实现一个服务发布多路RTSP流?


    我们在做Android平台轻量级RTSP服务和内网RTSP网关的时候,遇到过这样的问题,如何同时发布多路RTSP流出去?

    回答这个问题,实际上不难,大牛直播SDK在设计这个模块的时候,考虑到了一个Service带多路流的情况,以下是大概的技术实现:

    启动RTSP服务:

    启动RTSP服务的时候,你可以注意到OpenRtspServer()会返回rtsp_handle_,这个句柄对应一个RTSP Service。

    1. class ButtonRtspServiceListener implements OnClickListener {
    2. public void onClick(View v) {
    3. if (isRTSPServiceRunning) {
    4. stopRtspService();
    5. btnRtspService.setText("启动RTSP服务");
    6. btnRtspPublisher.setEnabled(false);
    7. isRTSPServiceRunning = false;
    8. return;
    9. }
    10. if(!OpenPushHandle())
    11. {
    12. return;
    13. }
    14. Log.i(TAG, "onClick start rtsp service..");
    15. rtsp_handle_ = libPublisher.OpenRtspServer(0);
    16. if (rtsp_handle_ == 0) {
    17. Log.e(TAG, "创建rtsp server实例失败! 请检查SDK有效性");
    18. } else {
    19. int port = 8554;
    20. if (libPublisher.SetRtspServerPort(rtsp_handle_, port) != 0) {
    21. libPublisher.CloseRtspServer(rtsp_handle_);
    22. rtsp_handle_ = 0;
    23. Log.e(TAG, "创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!");
    24. }
    25. //String user_name = "admin";
    26. //String password = "12345";
    27. //libPublisher.SetRtspServerUserNamePassword(rtsp_handle_, user_name, password);
    28. if (libPublisher.StartRtspServer(rtsp_handle_, 0) == 0) {
    29. Log.i(TAG, "启动rtsp server 成功!");
    30. } else {
    31. libPublisher.CloseRtspServer(rtsp_handle_);
    32. rtsp_handle_ = 0;
    33. Log.e(TAG, "启动rtsp server失败! 请检查设置的端口是否被占用!");
    34. }
    35. btnRtspService.setText("停止RTSP服务");
    36. btnRtspPublisher.setEnabled(true);
    37. isRTSPServiceRunning = true;
    38. }
    39. }
    40. }

    如何停止这个RTSP服务?

    1. //发布/停止RTSP流
    2. class ButtonRtspPublisherListener implements OnClickListener {
    3. public void onClick(View v) {
    4. if (isRTSPPublisherRunning) {
    5. stopRtspPublisher();
    6. btnRtspPublisher.setText("发布RTSP流");
    7. btnGetRtspSessionNumbers.setEnabled(false);
    8. btnRtspService.setEnabled(true);
    9. }
    10. else
    11. {
    12. Log.i(TAG, "onClick start rtsp publisher..");
    13. boolean startRet = StartRtspStream();
    14. if (!startRet) {
    15. Log.e(TAG, "Failed to call StartRtspStream().");
    16. return;
    17. }
    18. btnRtspPublisher.setText("停止RTSP流");
    19. btnGetRtspSessionNumbers.setEnabled(true);
    20. btnRtspService.setEnabled(false);
    21. }
    22. }
    23. };

    如何启动一个服务,发布多个RTSP流(对应不同的数据源和RTSP拉流URL)?

    实际上,只要确保,每个发布的RTSP流,对应一个publisherHandle,音视频数据投递,也是传递这个publisherHandle。

    1. private boolean StartRtspStream(long publisherHandle, String rtsp_stream_name)
    2. {
    3. if (isRTSPPublisherRunning)
    4. return false;
    5. libPublisher.SetRtspStreamName(publisherHandle, rtsp_stream_name);
    6. libPublisher.AddRtspStreamServer(publisherHandle, rtsp_handle_, 0);
    7. if (libPublisher.StartRtspStream(publisherHandle, 0) != 0)
    8. {
    9. Log.e(TAG, "调用发布rtsp流接口失败!");
    10. if (!isPushing)
    11. {
    12. libPublisher.SmartPublisherClose(publisherHandle);
    13. publisherHandle = 0;
    14. }
    15. return false;
    16. }
    17. isRTSPPublisherRunning = true;
    18. return true;
    19. }

    停止发布RTSP流:

    1. //停止发布RTSP流
    2. private void stopRtspPublisher(long publisherHandle)
    3. {
    4. if(!isRTSPPublisherRunning)
    5. return;
    6. isRTSPPublisherRunning = false;
    7. if (null == libPublisher || 0 == publisherHandle)
    8. return;
    9. libPublisher.StopRtspStream(publisherHandle);
    10. if (!isPushing && !isRTSPServiceRunning)
    11. {
    12. releasePublisherHandle();
    13. }
    14. }

    每一路发布的RTSP流,都对应一个event回调,回上来外部可以拉流的RTSP URL:

    1. class EventHandlePublisherV2 implements NTSmartEventCallbackV2 {
    2. @Override
    3. public void onNTSmartEventCallbackV2(long handle, int id, long param1, long param2, String param3, String param4, Object param5) {
    4. Log.i(TAG, "EventHandlePublisherV2: handle=" + handle + " id:" + id);
    5. String publisher_event = "";
    6. switch (id) {
    7. ...
    8. case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
    9. publisher_event = "RTSP服务URL: " + param3;
    10. break;
    11. ...
    12. }
    13. }
    14. }

    如果需要获取单个Service的会话链接数:

    1. //获取RTSP会话数
    2. class ButtonGetRtspSessionNumbersListener implements OnClickListener {
    3. public void onClick(View v) {
    4. if (libPublisher != null && rtsp_handle_ != 0) {
    5. int session_numbers = libPublisher.GetRtspServerClientSessionNumbers(rtsp_handle_);
    6. Log.i(TAG, "GetRtspSessionNumbers: " + session_numbers);
    7. PopRtspSessionNumberDialog(session_numbers);
    8. }
    9. }
    10. };

    以上是大概的设计思路,感兴趣的开发者可以参考。

  • 相关阅读:
    Handler消息传递机制
    SpringBoot基础知识
    聊一聊 GDB 调试程序时的几个实用命令
    [大师C语言(第十八篇)]C语言typedef背后技术详解
    Hudi第二章:集成Spark
    [网络] 前端大文件上传
    rtmp播放器
    基于Python代码的相关性热力图,VIF共线性诊断图及残差四图的使用及解释
    【逐步剖C++】-第二章-C++类和对象(下)
    pycharm使用
  • 原文地址:https://blog.csdn.net/renhui1112/article/details/133277848