1. 前言在安防监控、边缘网关、园区视频汇聚、工业视觉、无人值守站点、机器人、车载终端和云端视频接入等场景中现场摄像头或 NVR 通常通过 RTSP 输出视频流而上级平台、云直播平台、视频中台或 Web 播放链路往往更倾向于 RTMP 输入。这就带来一个非常典型的工程需求在 Linux arm64/aarch64 设备上部署一个轻量级转发模块将多路 RTSP 摄像头流统一接入然后按通道转推为 RTMP同时支持本地录像、定时截图、下载速度监控和异常状态管理。大牛直播SDKSmartMediaKitLinux arm64 版relaydemo展示的就是这样一套多路流媒体转发链路。它同时使用 SmartPlayer 拉流模块和 SmartPublisher 推流模块SmartPlayer 负责 RTSP/RTMP 拉流、PullStream 压缩包回调、录像、截图和下载速度事件SmartPublisher 负责接收外部编码音视频数据并推送到 RTMP ServerSmartLog 负责 SDK 日志输出RelaySDKWrapper负责将拉流、推流、录像等能力封装成单路 relay 对象主程序通过配置数组组织多路任务。本文结合 Linux arm64 版本的relaydemo系统说明多路 RTSP 转 RTMP 推送模块的集成方式。2. 模块定位relaydemo并不是一个单纯的播放器 Demo也不是普通的 RTMP 推流 Demo而是一个典型的拉流转推模块。它的核心价值在于RTSP/RTMP 源流 | SmartPlayer 拉流 | PullStream 获取压缩音视频包 | RelaySDKWrapper 回调桥接 | SmartPublisher 外部编码数据输入 | RTMP 推送到平台与“拉流解码 - 重新编码 - 推流”的转码方案不同relaydemo的常规转推链路主要处理压缩后的音视频包。视频数据可以不经过解码和重编码直接通过PostVideoEncodedDataV2()投递给 SmartPublisher再由 SmartPublisher 完成 RTMP 推送。这种方式有几个明显优势不做视频二次编码CPU 占用更低保留源流画质避免二次编码损失链路更短转推延迟更可控更适合 ARM 边缘设备上的多路并发同一路 SmartPlayer handle 还可以旁路做录像和截图适合构建轻量级视频协议转换网关。3. 典型使用场景3.1 安防摄像头 RTSP 汇聚上云在安防和视频监控项目中IPC、NVR 或国标网关常以 RTSP 形式提供视频流而云直播平台、视频中台、Web 播放系统或业务调度平台常要求 RTMP 输入。此时可将relaydemo改造成边缘转发网关IPC / NVR / RTSP 摄像头 | Linux arm64 边缘网关 | 多路 RTSP 转 RTMP | 云直播平台 / 企业视频平台 / 调度平台适合小区、园区、工地、门店、仓储、厂区、校园等多摄像头汇聚上云场景。3.2 边缘网关多路协议转换在很多项目中边缘网关既要接入局域网摄像头又要把部分关键通道转推到上级平台。SmartMediaKit relay 模块采用多实例 handle 方式每一路独立拉流、独立推流、独立录像适合构建轻量级协议转换网关。典型场景包括工业边缘盒子接入多路 IPC机器人多摄像头回传车载或移动布控设备转发无人值守站点远程视频接入内网 RTSP 流转为公网 RTMP 流。3.3 设备端录像与云端直播并行很多项目不仅要将视频推送到平台还要在设备侧本地留档。relaydemo支持按通道开启录像能力同一路拉流 handle | |-- PullStream 压缩包转 RTMP |-- SmartPlayer 本地录像这种方式适合关键通道本地备份弱网环境下本地补录告警场景留证现场故障复盘设备端长期录像和云端实时观看并存。3.4 定时截图与巡检取证对于部分场景业务并不需要持续录像只需要定时生成图片用于巡检、取证或状态记录。relaydemo支持通过 SmartPlayer 播放链路定时截图。适合巡检画面定时抓拍远程值守状态留存AI 轻量分析前置截图设备异常时取证低频预览类业务。3.5 RTSP/RTMP 源统一接入relaydemo中的pull_url_既可以是 RTSP也可以是 RTMP。这意味着业务侧可以将不同来源统一纳入同一套 relay 逻辑IPC RTSPNVR RTSP边缘流媒体 RTSP第三方 RTSP 服务已有 RTMP 流本地轻量级 RTSP 服务输出的流。4. SmartMediaKit 技术优势4.1 SmartPlayer 与 SmartPublisher 协同relay 模块同时使用 SmartPlayer 和 SmartPublisher模块作用libSmartPlayerSDK.so负责 RTSP/RTMP 拉流、PullStream 压缩包回调、录像、截图、下载速度事件libSmartPublisherSDK.so负责接收外部编码数据并推送 RTMPlibSmartLog.so负责 SDK 日志输出业务侧无需自行实现 RTSP 拉流、RTMP 推流、码流封装、录像封装和截图逻辑只需要按 SDK 生命周期组织通道即可。4.2 不重编码转推relay 的关键设计是“压缩包转发”。视频回调中收到的压缩视频包通过以下接口投递给推流端push_api_-PostVideoEncodedDataV2(push_handle, video_codec_id, data, size, info-is_key_frame_, info-timestamp_, info-presentation_timestamp_);音频回调中收到的压缩音频包通过以下接口投递push_api_-PostAudioEncodedData(push_handle, audio_codec_id, data, size, info-is_key_frame_, info-timestamp_, info-parameter_info_, info-parameter_info_size_);这种方式保留源流编码数据减少 CPU 开销降低画质损失也更适合多路并发转推。4.3 多路实例模型清晰Demo 使用RelayConfigItem描述每一路任务struct RelayConfigItem { const char* pull_url_; bool is_push_rtmp_; bool is_recorder_; bool is_capture_image_; };每一路可以独立配置拉流 URL是否转推 RTMP是否本地录像是否定时截图是否转发视频是否转发音频录像目录录像文件大小文件名前缀是否追加日期和时间。这类配置模型非常适合后续改造成 JSON、数据库或平台下发的通道配置。4.4 RTSP 兼容性和网络可观测性拉流 handle 打开时Demo 默认设置sdk_api_-SetBuffer(handle, buffer); sdk_api_-SetRtspAutoSwitchTcpUdp(handle, 1); sdk_api_-SetReportDownloadSpeed(handle, 1, 3);其中SetBuffer()用于设置拉流缓冲SetRtspAutoSwitchTcpUdp()用于 RTSP TCP/UDP 自动切换SetReportDownloadSpeed()用于定时上报下载速度。这对不同品牌 IPC、NVR、RTSP Server 的兼容性和生产运维都很重要。4.5 录像和截图能力内建SmartPlayer SDK 本身提供录像和截图能力。relay 模块可在转推链路之外直接对同一路源流进行录像或截图StartRecorder()/StopRecorder()SetRecorderDirectory()SetRecorderFileMaxSize()SetRecorderFileNameRuler()SetRecorderAudioTranscodeAAC()CaptureImage()。业务侧无需额外集成 MP4 封装或图片编码模块。5. Demo 工程结构说明relaydemo目录结构如下relaydemo/ ├── relaydemo.cpp ├── Makefile ├── readme.txt ├── libSmartPlayerSDK.so ├── libSmartPublisherSDK.so ├── libSmartLog.so ├── nt_smart_sdk/ │ └── linux/include/ │ ├── common/ │ ├── smart_player_sdk/ │ │ ├── nt_linux_smart_player_sdk.h │ │ └── smart_player_define.h │ └── smart_publisher_sdk/ │ ├── nt_linux_smart_publisher_sdk.h │ └── nt_smart_publisher_define.h ├── nt_smart_sdk_wrapper/ │ ├── nt_app_sdk_handle_wrapper.h │ ├── nt_app_sdk_handle_wrapper.cpp │ ├── nt_app_relay_sdk_wrapper.h │ └── nt_app_relay_sdk_wrapper.cpp └── aarch64/ ├── include/X11/ └── lib/关键文件说明文件说明relaydemo.cppDemo 主程序包含任务配置、SDK 初始化、多路任务启动/停止、定时截图nt_app_sdk_handle_wrapper.*SmartPlayer / SmartPublisher handle 的 C 封装nt_app_relay_sdk_wrapper.*单路 relay 封装负责拉流、转推、录像和回调桥接nt_linux_smart_player_sdk.hSmartPlayer 拉流、PullStream、录像、截图接口定义nt_linux_smart_publisher_sdk.hSmartPublisher 外部编码数据输入和 RTMP 推流接口定义smart_player_define.h拉流事件、PullStream 回调结构、录像规则等定义nt_smart_publisher_define.h发布模块的视频/音频源类型、事件和编码数据输入定义Makefilearm64 本地编译和 x86_64 交叉编译配置readme.txtDemo 运行说明从工程组织看Demo 将 SDK 原始 C 接口封装成 C wrapper业务主程序只需要关注多路配置、任务启动、主循环和退出释放。6. 环境要求与编译运行6.1 环境要求项目要求CPU 架构arm64 / aarch64操作系统Linux编译器gcc / g图形相关Makefile 链接 X11截图/播放相关能力依赖对应环境基础库glib-2.0、gio-2.0、pthread、libstdc、glibcSDK 动态库libSmartPlayerSDK.so、libSmartPublisherSDK.so、libSmartLog.so上线前建议检查ldd ./SmartStreamRelayDemo ldd ./libSmartPlayerSDK.so ldd ./libSmartPublisherSDK.so ldd ./libSmartLog.so重点确认不存在not found如果存在依赖缺失需要检查 SDK 动态库路径、系统运行库、glib/gio、X11、libstdc 和 glibc 版本。6.2 Makefile 链接项Demo 的 Makefile 主要链接以下库NT_LINK_LIBS -L. -lSmartPlayerSDK -L. -lSmartPublisherSDK -L. -lSmartLog NT_LINK_LIBS -lX11 -lglib-2.0 -lgio-2.0默认交叉编译配置NT_ARCH aarch64 NT_CROSS_COMPILE_PREFIX aarch64-linux-gnu- NT_ENABLE_EXTERNAL_LIB yes NT_EXTERNAL_LIB_PATH ./aarch646.3 arm64 设备本地编译如果直接在 ARM Linux 设备上编译cd relaydemo make NT_ENABLE_EXTERNAL_LIBno NT_CROSS_COMPILE_PREFIX参数说明参数说明NT_ENABLE_EXTERNAL_LIBno使用目标系统已安装的依赖库NT_CROSS_COMPILE_PREFIX置空后使用目标机本地 gcc/g 编译6.4 x86_64 主机交叉编译如果在 x86_64 Linux 主机上交叉编译cd relaydemo make需要提前安装aarch64-linux-gnu-gcc aarch64-linux-gnu-g6.5 运行 Demo编译产物为SmartStreamRelayDemo前台运行./SmartStreamRelayDemo后台运行nohup ./SmartStreamRelayDemo /dev/null 21 正常终止后台进程kill -s SIGINT pidDemo 中注册了SIGINT处理函数收到信号后会设置退出标记主循环退出后停止截图、转推和录像任务并释放 SDK 资源。6.6 运行前目录准备Demo 默认录像目录和截图目录为const char* rec_dir ./testrec; const char* capture_image_dir ./testcapture;运行前建议创建目录mkdir -p testrec testcapture chmod 755 testrec testcapture如果录像或截图失败优先检查目录是否存在、路径是否正确、运行用户是否具备写权限。7. 整体集成架构7.1 单路转推链路单路 RTSP 转 RTMP 的核心链路如下RTSP / RTMP 源 | SmartPlayer Open SetURL | StartPullStream() | 压缩视频包 / 压缩音频包回调 | RelaySDKWrapper | PostVideoEncodedDataV2() PostAudioEncodedData() | SmartPublisher | StartPublisher() | RTMP Server / 云直播平台 / 企业视频平台在这个链路中SmartPlayer 不负责显示画面主要用于拉流和输出压缩码流SmartPublisher 不采集摄像头或麦克风而是以外部编码数据模式接收码流并推送 RTMP。7.2 多路任务模型多路任务可以抽象为进程 | |-- SmartPlayerSDKAPI.Init() |-- NT_SmartPublisherSDKAPI.Init() | |-- Relay 1: rtsp://camera-1 - rtmp://server/live/stream1 |-- Relay 2: rtsp://camera-2 - rtmp://server/live/stream2 |-- Relay 3: rtsp://camera-3 - recorder only |-- Relay 4: rtsp://camera-4 - capture image only | |-- SIGINT / 服务停止 | |-- StopPublisher / StopPullStream / StopRecorder / StopPlay |-- Publisher.UnInit() |-- Player.UnInit()每一路 relay 都应具备独立状态、独立 URL、独立录像配置和独立异常处理。7.3 录像与截图旁路同一路 SmartPlayer handle 可以用于不同旁路能力同一路 SmartPlayer pull handle | |-- StartPullStream() 压缩包转 RTMP |-- StartRecorder() 本地录像 |-- StartPlay() CaptureImage() 定时截图Demo 在截图场景下会先创建一个PullStreamSDKHandleWrapper并StartPlay()如果该路同时需要转推或录像会通过AttachPullHandle()复用该 handle避免同一路源重复拉流。8. 核心 API 集中说明为了避免接口分散本节按集成流程集中说明主要 API。8.1 日志和 SDK 初始化SmartLogAPI log_api; memset(log_api, 0, sizeof(log_api)); GetSmartLogAPI(log_api); log_api.SetLevel(SL_INFO_LEVEL); log_api.SetPath((NT_PVOID)./);初始化 Player 和 PublisherSmartPlayerSDKAPI pull_api; NT_SmartPublisherSDKAPI push_api; memset(pull_api, 0, sizeof(pull_api)); GetSmartPlayerSDKAPI(pull_api); if (NT_ERC_OK ! pull_api.Init(0, nullptr)) { fprintf(stderr, pull_api.Init failed!\n); return false; } memset(push_api, 0, sizeof(push_api)); NT_GetSmartPublisherSDKAPI(push_api); if (NT_ERC_OK ! push_api.Init(0, nullptr)) { pull_api.UnInit(); fprintf(stderr, push_api.Init failed!\n); return false; }需要注意Player SDK 和 Publisher SDK 都需要初始化如果 Publisher 初始化失败应释放已经初始化成功的 Player进程退出时建议先停止所有任务再push_api.UnInit()最后pull_api.UnInit()。8.2 打开拉流 handlePullStreamSDKHandleWrapper::Open()的核心流程NT_HANDLE handle nullptr; sdk_api_-Open(handle, 0, nullptr); sdk_api_-SetEventCallBack(handle, this, OnSDKEvent); sdk_api_-SetBuffer(handle, buffer); sdk_api_-SetRtspAutoSwitchTcpUdp(handle, 1); sdk_api_-SetReportDownloadSpeed(handle, 1, 3); sdk_api_-SetURL(handle, url.c_str());说明接口说明Open()创建 SmartPlayer 实例SetEventCallBack()注册事件回调SetBuffer()设置缓冲Demo 默认传 0SetRtspAutoSwitchTcpUdp()开启 RTSP TCP/UDP 自动切换SetReportDownloadSpeed()每 3 秒上报下载速度SetURL()设置 RTSP/RTMP 源地址8.3 启动 PullStream转推链路通过 PullStream 获取压缩音视频数据pull_api_-SetPullStreamVideoDataCallBack(handle, this, OnPullVideoData); pull_api_-SetPullStreamAudioDataCallBack(handle, this, OnPullAudioData); pull_api_-SetPullStreamAudioTranscodeAAC(handle, 1); pull_api_-StartPullStream(handle);说明StartPullStream()用于获取未解码的压缩音视频数据视频回调中包含 codec id、关键帧标记、DTS、PTS音频回调中包含 codec id、timestamp 和 parameter infoSetPullStreamAudioTranscodeAAC()可将音频转为 AAC提高 RTMP 和 MP4 兼容性。8.4 打开推流 handle转推场景下Publisher 不采集本地摄像头和麦克风而是接收外部编码数据push_api_-Open(handle, NT_PB_E_VIDEO_OPTION_ENCODED_DATA, NT_PB_E_AUDIO_OPTION_ENCODED_DATA, 0, nullptr);这一步非常关键视频源设置为NT_PB_E_VIDEO_OPTION_ENCODED_DATA音频源设置为NT_PB_E_AUDIO_OPTION_ENCODED_DATA后续通过PostVideoEncodedDataV2()和PostAudioEncodedData()输入数据。8.5 设置 RTMP URL 并启动推流push_api_-SetURL(push_handle, rtmp_url.c_str(), nullptr); push_api_-StartPublisher(push_handle, nullptr);停止推流push_api_-StopPublisher(push_handle);生产环境中RTMP URL 建议从配置文件或平台下发不建议硬编码。8.6 视频包转发push_api_-PostVideoEncodedDataV2(push_handle, video_codec_id, data, size, info-is_key_frame_, info-timestamp_, info-presentation_timestamp_);字段说明字段说明video_codec_id视频编码类型例如 H.264data / size压缩视频包is_key_frame_是否关键帧timestamp_解码时间戳presentation_timestamp_显示时间戳8.7 音频包转发push_api_-PostAudioEncodedData(push_handle, audio_codec_id, data, size, info-is_key_frame_, info-timestamp_, info-parameter_info_, info-parameter_info_size_);注意事项如果源音频是 AACparameter_info_通常用于传递 AudioSpecificConfig如果业务不需要音频建议关闭音频转发如果源音频类型不确定可启用音频转 AAC推流有画面无声音时优先检查音频转发开关、源流音频和编码格式。8.8 停止与释放推荐释放顺序StopPlay() // 如果启用了截图播放链路 StopPublisher() StopPullStream() StopRecorder() Close() push_api.UnInit() pull_api.UnInit()Demo 中RelaySDKWrapper析构会兜底调用StopPushRtmp(); StopPull(); StopRecorder();生产环境建议仍然显式停止每一路任务便于状态记录和问题排查。9. 多路任务配置与管理9.1 Demo 配置方式Demo 中通过数组配置多路任务RelayConfigItem relay_conf_items[] { { rtsp://admin:password192.168.0.120:554/h264/ch1/main/av_stream, true, // is_push_rtmp false, // is_recorder false, // is_capture_image }, };字段说明字段说明pull_url_拉流地址可以是 RTSP 或 RTMPis_push_rtmp_是否将该路转推 RTMPis_recorder_是否对该路本地录像is_capture_image_是否对该路定时截图RTMP 推送基地址const char* rtmp_push_base_url rtmp://192.168.0.107/live/;Demo 根据通道序号生成目标推送 URLrtmp://192.168.0.107/live/linuxrelaytest1 rtmp://192.168.0.107/live/linuxrelaytest2 ...9.2 生产环境配置建议实际项目中建议将硬编码数组改为 JSON、数据库或平台下发配置例如[ { channelId: cam-001, pullUrl: rtsp://user:pass192.168.1.10:554/stream1, pushRtmpUrl: rtmp://live.example.com/live/cam001, enablePush: true, enableRecorder: true, enableSnapshot: false, relayVideo: true, relayAudio: true, recorderFileMaxSizeMB: 200, snapshotIntervalSec: 30 } ]每一路通道建议维护以下信息字段说明channel_id通道 IDpull_url拉流地址push_url推流地址enable_push是否转推enable_recorder是否录像enable_snapshot是否截图relay_video是否转发视频relay_audio是否转发音频state当前状态download_speed当前下载速度recorder_file当前录像文件last_error最近错误reconnect_count重连次数9.3 启动任务流程StartTasks()的核心逻辑可以概括为遍历 RelayConfigItem | 检查 pull_url 是否有效 | 如果开启截图 创建 PullStreamSDKHandleWrapper SetVideoFrameCallBack(I420) StartPlay() 保存 player handle | 如果需要推流或录像 创建 RelaySDKWrapper SetPullURL() 如果已有截图 handle则 AttachPullHandle() | 如果开启 RTMP SetRelayVideo(true) SetRelayAudio(true/false) StartPull() StartPushRtmp() | 如果开启录像 设置录像目录、大小、文件名前缀、日期时间规则 StartRecorder() | 如果 relay 正在工作 加入 relays 容器9.4 停止任务流程推荐停止流程停止截图播放 handle | 停止 RTMP 推送 | 停止 PullStream | 停止录像 | 释放 relay 对象 | Publisher UnInit | Player UnInit需要注意停止顺序应避免以下问题推流 handle 已释放但回调仍在投递数据PullStream 未停止导致回调继续触发录像文件未正常关闭截图播放 handle 未释放重连过程中重复创建 handle。10. 本地录像与定时截图10.1 本地录像Demo 使用 SmartPlayer 的录像能力录像配置示例relay_item-SetRecorderDirectory(./testrec); relay_item-SetRecorderFileMaxSize(200); relay_item-SetRecorderAudioTranscodeAAC(true); relay_item-SetRecorderAppendDate(true); relay_item-SetRecorderAppendTime(true); relay_item-SetRecorderVideo(true); relay_item-SetRecorderAudio(false); relay_item-SetRecorderFileNamePrefix(rt-1-); relay_item-StartRecorder();内部会调用pull_api_-SetRecorderVideo(handle, 1); pull_api_-SetRecorderAudio(handle, 0); pull_api_-SetRecorderDirectory(handle, recoder_directory_.c_str()); pull_api_-SetRecorderFileMaxSize(handle, recorder_file_max_size_ * 1024); pull_api_-SetRecorderFileNameRuler(handle, rec_name_ruler); pull_api_-SetRecorderCallBack(handle, this, OnRecorderHandle); pull_api_-SetRecorderAudioTranscodeAAC(handle, 1); pull_api_-StartRecorder(handle);录像文件命名规则NT_SP_RecorderFileNameRuler rec_name_ruler {0, nullptr, 0, 0}; rec_name_ruler.file_name_prefix_ rt-1-; rec_name_ruler.append_date_ 1; rec_name_ruler.append_time_ 1;建议录像目录提前创建并赋予写权限文件名前缀包含通道 ID按需开启音频录像如果音频格式不确定可开启音频转 AAC录像文件完成后可异步上传、入库或生成索引。10.2 定时截图Demo 通过 SmartPlayer 播放链路实现截图pull_api-SetVideoFrameCallBack(handle-Handle(), NT_SP_E_VIDEO_FRAME_FROMAT_I420, nullptr, OnPlayerSDKVideoFrameHandle); pull_api-StartPlay(handle-Handle());截图间隔const time_t capture_image_interval 30;截图调用player_api-CaptureImage(handle, MakeCaptureImageFileName(i).c_str(), nullptr, OnPlayerSDKCaptureImageCallBack);截图文件名类似./testcapture/tc-1-06-26-14-30-00.png建议截图目录提前创建多路截图避免同一秒同时触发过多请求截图频率不要过高视频帧回调优先使用 I420避免 RGB 转换增加性能开销定时截图适合巡检和状态留证不建议替代录像。11. 生产环境集成建议11.1 部署目录建议建议生产环境采用清晰目录结构/opt/smartrelay/ ├── bin/ │ └── smartrelay ├── lib/ │ ├── libSmartPlayerSDK.so │ ├── libSmartPublisherSDK.so │ └── libSmartLog.so ├── conf/ │ └── relay_channels.json ├── logs/ ├── rec/ └── capture/启动脚本示例#!/bin/bash APP_HOME/opt/smartrelay export LD_LIBRARY_PATH$APP_HOME/lib:$LD_LIBRARY_PATH cd $APP_HOME/bin ./smartrelay --config $APP_HOME/conf/relay_channels.json11.2 URL 与凭据安全RTSP URL 经常包含用户名和密码日志中应做脱敏rtsp://admin:******192.168.0.120:554/...RTMP URL 如果包含 token、鉴权串或业务身份也应避免明文输出到普通日志。建议URL 从配置文件或平台接口读取配置文件权限限制为业务进程可读日志中只保留必要定位信息通道 ID 与 URL 分开记录异常日志中避免打印完整密码和 token。11.3 状态机建议每一路 relay 建议维护状态机Idle | OpeningPull | Pulling | |-- Pushing |-- Recording |-- Snapshotting | Failed | Reconnecting | Stopping | Stopped状态机中建议区分拉流状态推流状态录像状态截图状态网络状态最近错误事件。11.4 重连与恢复策略转推链路涉及拉流端和推流端两侧异常建议分别处理异常类型建议处理RTSP 拉流失败重建 Pull handleRTSP 源断开停止当前 PullStream 后重新拉流RTMP 推流失败重建 Push handleRTMP 服务重启按退避策略重推录像失败独立告警不一定影响转推截图失败限频告警不影响主链路URL 鉴权失败不建议高频无限重试目录无权限明确告警等待配置修复11.5 监控指标建议生产环境建议采集以下指标指标说明拉流状态每路源是否正常推流状态每路 RTMP 是否在线下载速度判断源流码率和网络状态推流 URL记录目标平台录像文件名当前或最近录像文件录像目录剩余空间避免磁盘写满截图成功/失败次数判断截图链路健康重连次数判断网络或源端稳定性CPU / 内存判断设备负载网络上下行判断带宽是否充足通道数判断并发是否超出设备能力11.6 并发性能建议多路转推并发能力受以下因素影响源流分辨率源流码率是否转发音频是否开启音频转 AAC是否本地录像是否定时截图磁盘写入性能网络上行带宽CPU 和内存规格IPC/NVR 对并发拉流数量的限制。由于视频链路不重编码转推 CPU 压力通常明显低于转码方案。但录像、截图、音频转码和多路网络 IO 仍然需要做压测。12. 常见问题排查12.1 拉不到 RTSP 流排查方向RTSP URL 是否正确用户名和密码是否正确摄像头或 NVR 是否允许当前账号访问是否达到摄像头最大连接数VLC、ffplay 或 SmartPlayer 是否可单独播放是否开启 RTSP TCP/UDP 自动切换网络、防火墙、路由是否可达SDK 日志中是否有连接失败信息。12.2 RTMP 推送失败排查方向RTMP Server 地址、端口、app、stream 是否正确防火墙是否允许访问RTMP 服务是否允许发布推流 URL 是否被其他进程占用Publisher handle 是否以ENCODED_DATA模式打开是否已经收到上游压缩视频包是否调用了StartPublisher()SDK 日志是否有连接失败事件。12.3 推流有画面无声音排查方向是否调用SetRelayAudio(true)源流是否包含音频源音频编码是否被 RTMP Server 或播放端支持是否需要开启SetPullStreamAudioTranscodeAAC(true)PostAudioEncodedData()是否持续被调用如果业务不需要音频可明确关闭音频转发。12.4 录像失败排查方向录像目录是否存在录像目录是否可写磁盘空间是否充足是否开启SetRecorderVideo(true)或SetRecorderAudio(true)单文件大小是否合理文件名前缀是否包含非法字符录像目录是否包含非英文字符。12.5 截图失败排查方向截图目录是否存在目录是否可写是否已经StartPlay()源流是否有视频截图频率是否过高回调result是否为NT_ERC_OK多路截图是否导致 CPU 峰值过高。12.6 CPU 或内存占用高优化方向关闭不必要的音频转发关闭不必要的截图降低截图频率减少录像路数关闭不必要的播放/解码链路避免同一路源重复拉流优先复用 Pull handle控制单设备并发通道数检查是否误走了解码或转码链路。12.7 多路运行一段时间后不稳定排查方向每路异常后是否正确Stop/Close断线重连是否创建了未释放的 handle录像目录是否写满RTMP 服务是否限制连接数IPC/NVR 是否限制并发拉流数日志是否过量写入磁盘是否存在频繁截图导致 CPU 峰值是否存在 URL 配置错误导致高频重连。13. 上线验收 Checklist13.1 环境验收检查项是否完成目标设备为 arm64/aarch64□SmartStreamRelayDemo可正常启动□libSmartPlayerSDK.so可正常加载□libSmartPublisherSDK.so可正常加载□libSmartLog.so可正常加载□ldd检查无not found□glib/gio/X11 依赖满足□录像目录可写□截图目录可写□网络可访问 RTSP 源和 RTMP 服务□13.2 功能验收检查项是否完成单路 RTSP 转 RTMP 成功□多路 RTSP 转 RTMP 成功□RTMP 播放端可正常播放□开启音频转发后声音正常□关闭音频转发后视频正常□本地录像文件生成成功□录像文件可播放□定时截图成功□下载速度事件正常上报□SIGINT 后进程可正常退出□退出后资源释放完整□13.3 稳定性验收检查项是否完成多路长时间运行无崩溃□断网恢复后可按策略重连□RTMP 服务重启后可恢复推送□摄像头重启后可恢复拉流□录像切片稳定□截图不会导致 CPU 峰值不可控□内存无持续增长□磁盘满、目录无权限等异常有明确告警□多路停止/重启无资源泄漏□14. 与当前 Demo 的对应关系文档内容对应文件多路任务配置、SDK 初始化、启动/停止任务、定时截图relaydemo.cpp拉流 handle 封装、事件分发nt_smart_sdk_wrapper/nt_app_sdk_handle_wrapper.cpp推流 handle 封装nt_smart_sdk_wrapper/nt_app_sdk_handle_wrapper.cpp单路 relay 逻辑、PullStream 回调、RTMP 推送、录像nt_smart_sdk_wrapper/nt_app_relay_sdk_wrapper.cppRelay 对外接口nt_smart_sdk_wrapper/nt_app_relay_sdk_wrapper.hSmartPlayer 接口nt_smart_sdk/linux/include/smart_player_sdk/nt_linux_smart_player_sdk.hSmartPublisher 接口nt_smart_sdk/linux/include/smart_publisher_sdk/nt_linux_smart_publisher_sdk.h编译配置Makefile运行说明readme.txt15. 总结整体来看大牛直播SDKSmartMediaKitLinux arm64 平台多路 RTSP 转 RTMP 推送模块并不是一个简单的“拉一路流再推一路流”的示例而是一套面向边缘网关、安防汇聚、工业视觉和云端视频接入场景的轻量级流媒体转发能力组件。在实际项目中RTSP 摄像头、NVR、边缘流媒体服务和云端 RTMP 平台之间经常存在协议不一致、接入方式不统一、设备资源有限、录像留证和运维监控要求较高等问题。SmartMediaKit relay 模块通过 SmartPlayer 拉流、PullStream 压缩包回调和 SmartPublisher 外部编码数据输入的组合方式实现了不重编码的视频转推链路在降低 CPU 占用的同时也减少了画质损失和链路复杂度。从relaydemo可以看出该模块的集成流程比较清晰进程级初始化 SmartPlayer 和 SmartPublisher每一路创建独立的 relay wrapper按通道设置拉流 URL、推流 URL、录像和截图策略通过 PullStream 回调将压缩音视频包投递给 Publisher运行中通过下载速度、录像回调和业务状态机监控每路状态退出时再逐路停止推流、拉流、录像和截图链路。对于多路 RTSP 摄像头汇聚上云场景可以直接参考relaydemo的多路配置和 wrapper 封装方式将其改造成边缘转发服务对于需要设备端本地留证的项目可以按通道开启录像对于巡检和低频取证类场景可以结合定时截图能力对于需要长期运行的生产环境则建议重点完善配置管理、URL 脱敏、状态机、异常重连、磁盘空间监控和通道级运维指标。对于需要在 Linux arm64 设备上快速构建多路 RTSP/RTMP 拉流、RTSP 转 RTMP 推送、本地录像和定时截图能力的项目大牛直播SDKSmartMediaKit可以作为底层转发能力组件帮助开发者减少协议适配、码流转发、RTMP 封装、录像截图和异常处理等方面的重复开发工作把更多精力放在设备管理、平台接入、业务规则和行业应用本身。 CSDN官方博客音视频牛哥-CSDN博客