• Linux平台如何实现采集音视频数据并注入轻量级RTSP服务?


    技术背景

    好多开发者,问我们最多的问题是,为什么要设计轻量级RTSP服务?轻量级RTSP服务,和RTSP服务有什么区别?

    针对这个问题,我们的回答是:轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP服务或者RTMP服务,RTSP服务,并发或功能相对强大,数据注入模式一般是外部直接推流到RTSP服务(目前大多流媒体服务,以RTMP居多,RTSP的相对较少,或者说,可以商用的RTSP服务,相对较少,音视频数据推送这块,RTMP推送为主,很少有RTSP推流),轻量级RTSP服务,直接部署在数据源测,相当于采集到的屏幕、摄像头、麦克风数据,直接编码注入本地的轻量级RTSP服务,对外提供个可供拉流的RTSP URL,说到这里,轻量级RTSP服务,更像一个IPC摄像头,侧重的不是并发,而是便捷。

    设计架构图

    Windows、Android、iOS平台的轻量级RTSP服务,不再赘述,之前都有描述,今天介绍的是Linux平台下的轻量级RTSP服务。

    和其他平台一样,我们Linux平台依然实现的是本地的音视频数据(如屏幕、摄像头、麦克风),编码打包后,汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,轻量级RTSP服务,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。

    功能设计

    •  [基础功能]支持常规的屏幕、摄像机、音频采集处理等;
    •  [音频格式]AAC;
    •  [视频格式]H.264、H.265;
    •  [协议类型]RTSP;
    •  [传输模式]支持单播和组播模式;
    •  [端口设置]支持RTSP端口设置;
    •  [鉴权设置]支持RTSP鉴权用户名、密码设置;
    •  [获取session连接数]支持获取当前RTSP服务会话连接数;
    •  [多服务支持]支持同时创建多个内置RTSP服务;
    •  [H.265支持]Windows内置rtsp server支持发布H.265视频(64位库);
    •  [RTSP url回调]支持设置后的rtsp url通过event回调到上层。

    接口设计

    RTSP Server操作接口设计:

    1. /*
    2. * nt_linux_smart_publisher_sdk.h
    3. * Created by daniusdk.com
    4. */
    5. /*+++rtsp server操作接口+++*/
    6. /*
    7. * 创建一个rtsp server
    8. * pRtspServerHandle: rtsp server 句柄
    9. * reserve:保留参数传0
    10. * 成功返回 NT_ERC_OK
    11. */
    12. NT_UINT32(NT_API *OpenRtspServer)(NT_PHANDLE pRtspServerHandle, NT_INT32 reserve);
    13. /*
    14. * 设置rtsp server 监听端口, 在StartRtspServer之前必须要设置端口
    15. * rtsp_server_handle: rtsp server 句柄
    16. * port: 端口号,可以设置为554,或者是1024到65535之间,其他值返回失败
    17. * 成功返回 NT_ERC_OK
    18. */
    19. NT_UINT32(NT_API *SetRtspServerPort)(NT_HANDLE rtsp_server_handle, NT_INT32 port);
    20. /*
    21. * 设置rtsp server 鉴权用户名和密码, 这个可以不设置,只有需要鉴权的再设置
    22. * rtsp_server_handle: rtsp server 句柄
    23. * user_name: 用户名,必须是英文
    24. * password:密码,必须是英文
    25. * 成功返回 NT_ERC_OK
    26. */
    27. NT_UINT32(NT_API *SetRtspServerUserNamePassword)(NT_HANDLE rtsp_server_handle, NT_PCSTR user_name, NT_PCSTR password);
    28. /*
    29. * 设置rtsp server 组播, 如果server设置成组播就不能单播,组播和单播只能选一个, 一般来说单播网络设备支持的好,wifi组播很多路由器不支持
    30. * rtsp_server_handle: rtsp server 句柄
    31. * is_multicast: 是否组播, 1为组播, 0为单播, 其他值接口返回错误, 默认是单播
    32. * 成功返回 NT_ERC_OK
    33. */
    34. NT_UINT32(NT_API *SetRtspServerMulticast)(NT_HANDLE rtsp_server_handle, NT_INT32 is_multicast);
    35. /*
    36. * 设置rtsp server 组播组播地址
    37. * rtsp_server_handle: rtsp server 句柄
    38. * multicast_address: 组播地址
    39. * 如果设置的不是组播地址, 将返回错误
    40. * 组播地址范围说明: [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]
    41. * 成功返回 NT_ERC_OK
    42. */
    43. NT_UINT32(NT_API *SetRtspServerMulticastAddress)(NT_HANDLE rtsp_server_handle, NT_PCSTR multicast_address);
    44. /*
    45. * 获取rtsp server当前的客户会话数, 这个接口必须在StartRtspServer之后再调用
    46. * rtsp_server_handle: rtsp server 句柄
    47. * session_numbers: 会话数
    48. * 成功返回 NT_ERC_OK
    49. */
    50. NT_UINT32(NT_API *GetRtspServerClientSessionNumbers)(NT_HANDLE rtsp_server_handle, NT_INT32* session_numbers);
    51. /*
    52. * 启动rtsp server
    53. * rtsp_server_handle: rtsp server 句柄
    54. * reserve: 保留参数传0
    55. * 成功返回 NT_ERC_OK
    56. */
    57. NT_UINT32(NT_API *StartRtspServer)(NT_HANDLE rtsp_server_handle, NT_INT32 reserve);
    58. /*
    59. * 停止rtsp server
    60. * rtsp_server_handle: rtsp server 句柄
    61. * 成功返回 NT_ERC_OK
    62. */
    63. NT_UINT32(NT_API *StopRtspServer)(NT_HANDLE rtsp_server_handle);
    64. /*
    65. * 关闭rtsp server
    66. * 调用这个接口之后rtsp_server_handle失效,
    67. * 成功返回 NT_ERC_OK
    68. */
    69. NT_UINT32 (NT_API *CloseRtspServer)(NT_HANDLE rtsp_server_handle);
    70. /*---rtsp server操作接口---*/

    发布RTSP流相关接口设计:

    1. /*
    2. * nt_linux_smart_publisher_sdk.h
    3. * Created by daniusdk.com
    4. */
    5. /*+++发布rtsp流相关接口+++*/
    6. /*
    7. * 设置rtsp的流名称
    8. * stream_name: 流程名称,不能为空字符串,必须是英文
    9. * 这个作用是: 比如rtsp的url是:rtsp://192.168.0.111/test, test就是设置下去的stream_name
    10. * 成功返回 NT_ERC_OK
    11. */
    12. NT_UINT32(NT_API *SetRtspStreamName)(NT_HANDLE handle, NT_PCSTR stream_name);
    13. /*
    14. * 给要发布的rtsp流设置rtsp server, 一个流可以发布到多个rtsp server上,rtsp server的创建启动请参考OpenRtspServer和StartRtspServer接口
    15. * handle: 推送实例句柄
    16. * rtsp_server_handle:rtsp server句柄
    17. * reserve: 保留参数,传0
    18. */
    19. NT_UINT32(NT_API *AddRtspStreamServer)(NT_HANDLE handle, NT_HANDLE rtsp_server_handle, NT_INT32 reserve);
    20. /*
    21. * 清除设置的rtsp server
    22. */
    23. NT_UINT32(NT_API *ClearRtspStreamServer)(NT_HANDLE handle);
    24. /*
    25. 启动rtsp流
    26. reserve: 保留参数,传0
    27. */
    28. NT_UINT32(NT_API *StartRtspStream)(NT_HANDLE handle, NT_INT32 reserve);
    29. /*
    30. 停止rtsp流
    31. */
    32. NT_UINT32(NT_API *StopRtspStream)(NT_HANDLE handle);
    33. /*---发布rtsp流相关接口---*/

    调用实现

    启动RTSP Server:

    1. NT_HANDLE start_rtsp_server(NT_SmartPublisherSDKAPI* push_api, int port, std::string user_name, std::string password) {
    2. NT_HANDLE rtsp_server_handle = nullptr;
    3. if (NT_ERC_OK != push_api->OpenRtspServer(&rtsp_server_handle, 0)) {
    4. fprintf(stderr, "OpenRtspServer failed\n");
    5. return nullptr;
    6. }
    7. if (nullptr == rtsp_server_handle) {
    8. fprintf(stderr, "rtsp_server_handle is null\n");
    9. return nullptr;
    10. }
    11. if (NT_ERC_OK != push_api->SetRtspServerPort(rtsp_server_handle, port)) {
    12. push_api->CloseRtspServer(rtsp_server_handle);
    13. return nullptr;
    14. }
    15. if (!user_name.empty() && !password.empty())
    16. push_api->SetRtspServerUserNamePassword(rtsp_server_handle, user_name.c_str(), password.c_str());
    17. if (NT_ERC_OK == push_api->StartRtspServer(rtsp_server_handle, 0))
    18. return rtsp_server_handle;
    19. fprintf(stderr, "StartRtspServer failed\n");
    20. push_api->CloseRtspServer(rtsp_server_handle);
    21. return nullptr;
    22. }

    停止RTSP Server:

    1. void stop_rtsp_server(NT_SmartPublisherSDKAPI* push_api, NT_HANDLE& rtsp_server_handle) {
    2. if (nullptr == rtsp_server_handle)
    3. return;
    4. NT_HANDLE handle = rtsp_server_handle;
    5. rtsp_server_handle = nullptr;
    6. push_api->StopRtspServer(handle);
    7. push_api->CloseRtspServer(handle);
    8. }

    开始发布RTSP Stream:

    1. bool start_rtsp_stream(NT_SmartPublisherSDKAPI* push_api, NT_HANDLE rtsp_server_handle, NT_HANDLE handle, const std::string stream_name) {
    2. push_api->SetRtspStreamName(handle, stream_name.c_str());
    3. push_api->ClearRtspStreamServer(handle);
    4. push_api->AddRtspStreamServer(handle, rtsp_server_handle, 0);
    5. if (NT_ERC_OK != push_api->StartRtspStream(handle, 0))
    6. return false;
    7. return true;
    8. }

    如需停止RTSP流的发布,直接调用:

    	stop_rtsp_server(&push_api, rtsp_server_handle);

    如果需要采集到的音视频数据预览,调用预览接口即可:

    1. // 开启预览,也可以不开启, 根据需求来
    2. push_api.SetPreviewXWindow(push_handle, "", sub_wid);
    3. push_api.StartPreview(push_handle, 0, nullptr);

    总结

    轻量级RTSP服务,并发这块不是强项,不过确实解决了单独部署RTSP或RTMP服务的痛点,减少了工程实施成本,在并发量要求不高的场景下,非常方便。

  • 相关阅读:
    面试经典150题——Day12
    大学生个人网页模板 简单网页制作作业成品 极简风格个人介绍HTML网页设计代码下载
    【JUC系列-05】通过源码分析AQS和ReentrantLock的底层原理
    [bug总结]: Feign调用GET请求找不到请求体实体类
    内存池的面试整理
    Java基础入门·File类的使用
    Ourphp建站系统存在SQL注入
    阿里巴巴对裁员谣言报警
    【二叉树的存储及遍历】
    Flutter笔记:AnimationMean、AnimationMax 和 AnimationMin 三个类的用法
  • 原文地址:https://blog.csdn.net/renhui1112/article/details/132789145