文档概述

本文介绍大牛直播SDK(SmartMediaKit)在 Windows 平台下 C++ 版 RTMP 直播推流模块与轻量级 RTSP 服务模块的集成方法,适用于 MFC、Win32、C++ 桌面客户端、行业终端软件、工控机应用、局域网音视频分发系统等场景。

本文以 Windows C++ 推流 Demo 为基础,围绕 SDK 初始化、推流实例创建、音视频采集源选择、视频编码参数配置、RTMP 推流、内置轻量级 RTSP 服务、事件回调、本地预览、录像与截图等关键流程进行说明。Demo 底层通过 SmartPublisherSDK.dll 提供 C 接口能力,上层 C++ 工程通过 NT_SmartPublisherSDKAPI 函数表完成统一调用。上传的 SDK 头文件中也明确提供了 InitUnInitOpenCloseSetEventCallBack 等基础接口。

RTMP 推流模块面向实时音视频应用,可将本地采集或外部输入的音视频数据推送至 RTMP 服务器、CDN 或业务直播平台;轻量级 RTSP 服务模块则以内置服务方式,在无需单独部署流媒体服务器的情况下,对外生成可拉流访问的 RTSP URL。官网资料也将轻量级 RTSP 服务定义为推送端 SDK 内置的 RTSP 服务模块,可用于摄像头、麦克风、屏幕采集和外部编码数据等本地音视频输入场景。


1. 产品定位

大牛直播SDK(SmartMediaKit)Windows 推流 SDK 主要面向低延迟、稳定性和工程可控性要求较高的实时音视频系统。它不是单一的“摄像头推流工具”,而是一个可嵌入业务系统的音视频采集、编码、推流和局域网分发能力模块。

在 Windows 平台下,RTMP 推流模块主要解决“采集端到服务器端”的实时推送问题;轻量级 RTSP 服务模块主要解决“本机生成 RTSP URL,供局域网客户端直接拉流”的问题。两者可以独立使用,也可以在同一个推流实例中组合使用。

轻量级 RTSP 服务适合内网低并发、低延迟实时分发场景,官网资料明确提到其可用于安防监控、智慧教室、无纸化会议、工业生产、医疗健康、智能物联网等局域网音视频应用。


2. 适用场景

场景 说明
Windows 摄像头 RTMP 推流 采集本机摄像头和麦克风,将音视频推送到 RTMP Server、CDN 或业务平台
Windows 屏幕采集推流 采集桌面画面,可用于会议同屏、电子教室、远程协助、工控画面回传
窗口采集推流 对指定窗口进行采集,适合特定业务窗口画面输出
摄像头 + 屏幕合成 支持桌面与摄像头叠加、切换、画中画等多层合成场景
局域网 RTSP 分发 不部署独立流媒体服务器,由 SDK 内置 RTSP 服务直接输出 RTSP URL
RTMP + RTSP 同时输出 同一路采集数据同时推送 RTMP,并通过本地 RTSP 服务给局域网客户端播放
本地录像与截图 推流或预览过程中可按需扩展本地录像、截图能力
低延迟行业应用 适用于安防监控、工业视觉、应急指挥、远程巡检、智慧教室等实时性要求较高的场景

3. 开发环境与工程依赖

3.1 推荐环境

项目 说明
操作系统 Windows 7 及以上
开发语言 C++
UI 框架 MFC / Win32,Demo 以 MFC Dialog 为例
SDK 库 SmartPublisherSDK.dll / SmartPublisherSDK.lib
核心头文件 nt_smart_publisher_sdk.hnt_smart_publisher_define.hnt_common_media_define.h
平台架构 x86 / x64 需与 SDK 库架构保持一致

RTMP 推流官网资料中,Windows 平台能力包括 H.264/H.265 视频编码、AAC/Speex 音频编码、RTMP 推流、纯音频/纯视频/音视频推送、屏幕/摄像头采集、DXGI 采集、推送端预览、静音、状态回调、窗口采集、动态水印、快照、外部音视频数据接入、录像扩展等。发布文档中建议只写当前 Demo 或当前授权包实际开放的能力,避免把跨平台能力混写到 Windows C++ 集成说明中。

3.2 工程文件说明

文件 / 模块 说明
SmartPublisherDemoDlg.cpp/.h Demo 主对话框,负责 UI 控制、SDK 初始化、推流、RTSP 服务、录像、预览和事件分发
nt_smart_publisher_sdk.h SDK C 接口函数表、回调类型、核心 API 声明
nt_smart_publisher_define.h 推流事件、视频源、音频源、图像格式、图层类型等定义
nt_common_media_define.h 媒体类型和 Codec ID 定义,如 H.264、H.265、AAC、Speex 等
nt_rtsp_server_config_dlg.cpp/.h RTSP 服务配置对话框,负责端口、鉴权、组播、会话数等配置
nt_pb_ui_preview_wnd.cpp/.h 推流端预览窗口,接收 RGB32 图像并绘制
nt_smart_publisher_dlg.cpp/.h 视频合成相关配置,如屏幕层、摄像头层、图片层等

4. 推荐工程分层

建议业务工程不要直接把所有 SDK 调用堆在 UI 事件中,而是按以下方式分层:

这种分层方式的好处是:UI 层只处理业务状态和用户交互,SDK 调用集中管理,后续如果要封装成业务 SDK、服务进程或无界面采集程序,也更容易迁移。


5. SDK 初始化与生命周期管理

5.1 获取 SDK API 函数表

Windows C++ Demo 通过 NT_GetSmartPublisherSDKAPI() 获取 NT_SmartPublisherSDKAPI 函数表。获取成功后,所有 SDK 能力均通过该结构体中的函数指针调用。

NT_SmartPublisherSDKAPI publisher_api_;
NT_HANDLE publisher_handle_ = nullptr;

bool InitPublisherSDK()
{
    memset(&publisher_api_, 0, sizeof(publisher_api_));

    if (NT_ERC_OK != NT_GetSmartPublisherSDKAPI(&publisher_api_))
    {
        // SDK 加载失败,检查 DLL、运行库和平台架构是否匹配
        return false;
    }

    if (NT_ERC_OK != publisher_api_.Init(0, nullptr))
    {
        return false;
    }

    return true;
}

Init() 属于进程级初始化,通常在程序启动时调用一次;UnInit() 应在所有推流实例、RTSP 服务实例、录像和预览资源释放后再调用。上传文档也明确建议区分进程级 Init/UnInit 与实例级 Open/Close


6. 创建推流实例

6.1 视频源与音频源选择

调用 Open() 创建推流实例时,需要指定视频源和音频源。SDK 头文件中定义的视频源包括:无视频、屏幕采集、摄像头采集、视频合成、外部编码视频数据和窗口采集;音频源包括:无音频、麦克风、扬声器、麦克风与扬声器混音、外部编码音频、外部 PCM 等。

常见组合如下:

业务场景 video_option audio_option
纯屏幕推流 NT_PB_E_VIDEO_OPTION_SCREEN 按需选择麦克风、扬声器或无音频
摄像头推流 NT_PB_E_VIDEO_OPTION_CAMERA NT_PB_E_AUDIO_OPTION_CAPTURE_MIC
屏幕 + 摄像头合成 NT_PB_E_VIDEO_OPTION_LAYER 麦克风 / 扬声器 / 混音
指定窗口采集 NT_PB_E_VIDEO_OPTION_WINDOW 按需选择
外部编码视频输入 NT_PB_E_VIDEO_OPTION_ENCODED_DATA 按实际音频源选择

示例代码:

bool OpenPublisherHandle()
{
    if (publisher_handle_ != nullptr)
        return true;

    NT_UINT32 video_option = NT_PB_E_VIDEO_OPTION_SCREEN;
    NT_UINT32 audio_option = NT_PB_E_AUDIO_OPTION_CAPTURE_MIC;

    NT_UINT32 ret = publisher_api_.Open(
        &publisher_handle_,
        video_option,
        audio_option,
        0,
        nullptr);

    if (NT_ERC_OK != ret || publisher_handle_ == nullptr)
    {
        return false;
    }

    publisher_api_.SetEventCallBack(
        publisher_handle_,
        reinterpret_cast<NT_PVOID>(GetSafeHwnd()),
        NT_PB_SDKPublisherEventHandle);

    return true;
}

Demo 中也是先根据 UI 选择确定 video_optionaudio_option,再调用 Open() 创建 publisher_handle_,随后注册事件回调。


7. 视频采集配置

7.1 屏幕采集

屏幕采集适合桌面同屏、课件演示、工控画面输出等场景。可根据业务需要设置采集区域、帧率、码率和 DXGI 采集方式。

publisher_api_.SetScreenClip(
    publisher_handle_,
    left,
    top,
    width,
    height);

publisher_api_.SetFrameRate(publisher_handle_, 15);

// Windows 8 及以上可按需启用 DXGI 屏幕采集
publisher_api_.EnableDXGIScreenCapturer(publisher_handle_, 1);

注意:屏幕裁剪宽高应按 SDK 要求进行对齐处理,避免编码器或采集模块出现异常。

7.2 摄像头采集

摄像头采集流程通常包括:枚举摄像头、选择设备、选择分辨率和帧率,然后设置摄像头基础参数。

publisher_api_.SetVideoCaptureDeviceBaseParameter(
    publisher_handle_,
    camera_id_utf8,
    width,
    height);

publisher_api_.SetFrameRate(publisher_handle_, frame_rate);

// 可选:摄像头翻转和旋转
publisher_api_.FlipVerticalCamera(publisher_handle_, is_flip_vertical);
publisher_api_.FlipHorizontalCamera(publisher_handle_, is_flip_horizontal);
publisher_api_.RotateCamera(publisher_handle_, degrees);

Demo 中摄像头采集会根据当前选择的摄像头、分辨率和帧率调用 SetVideoCaptureDeviceBaseParameter()SetFrameRate(),并支持摄像头垂直翻转、水平翻转和旋转设置。

7.3 窗口采集

窗口采集适合只输出某个业务窗口内容的场景。使用前需要先选择目标窗口,并确认窗口句柄有效。

publisher_api_.SetCaptureWindow(publisher_handle_, target_hwnd);
publisher_api_.SetCaptureWindowWay(publisher_handle_, 1); // 1=GDI DC,2=WR,按系统支持情况选择

对于窗口大小可能动态变化的场景,建议结合码率组或动态码率策略,避免窗口变大后画质明显下降。

7.4 视频合成

当需要实现“屏幕 + 摄像头”“摄像头 + 图片水印”“窗口 + 图层叠加”等效果时,可使用 NT_PB_E_VIDEO_OPTION_LAYER 模式,并通过 SetLayersConfig() 配置多层画面。

SDK 头文件中定义的视频合成层包括屏幕层、摄像头层、RGBA 矩形层、图片层、外部视频帧层和窗口层。

// 示例:屏幕作为底层,摄像头作为右下角叠加层
NT_PB_ScreenLayerConfig screen_layer = {};
screen_layer.base_.type_ = NT_PB_E_LAYER_TYPE_SCREEN;
screen_layer.base_.index_ = 0;
screen_layer.base_.enable_ = 1;
screen_layer.base_.region_.x_ = 0;
screen_layer.base_.region_.y_ = 0;
screen_layer.base_.region_.width_ = output_width;
screen_layer.base_.region_.height_ = output_height;

NT_PB_CameraLayerConfig camera_layer = {};
camera_layer.base_.type_ = NT_PB_E_LAYER_TYPE_CAMERA;
camera_layer.base_.index_ = 1;
camera_layer.base_.enable_ = 1;
camera_layer.base_.region_.x_ = output_width - 320;
camera_layer.base_.region_.y_ = output_height - 240;
camera_layer.base_.region_.width_ = 320;
camera_layer.base_.region_.height_ = 240;
strncpy(camera_layer.device_unique_id_utf8_, camera_id_utf8, sizeof(camera_layer.device_unique_id_utf8_) - 1);

const NT_PB_LayerBaseConfig* layers[] = {
    &screen_layer.base_,
    &camera_layer.base_
};

publisher_api_.SetLayersConfig(publisher_handle_, 0, layers, 2, 0, nullptr);

SetLayersConfig() 通常应在启动推流、启动 RTSP 流或启动录像前完成。运行过程中,如需启用/禁用某一层或调整层位置,可使用 EnableLayer()UpdateLayerRegion() 等接口。SDK 头文件中也对这些图层配置与动态更新接口进行了定义。


8. 视频编码参数配置

视频编码参数通常在 Open() 成功后、StartPublisher()StartRtspStream() 之前设置。

8.1 编码类型

Windows C++ Demo 可根据实际环境选择 H.264 或 H.265,并支持软编码或硬编码方式。SDK 头文件中 SetVideoEncoder() 用于设置软硬编码类型、编码器 ID、Codec ID 和 GPU 参数;其中 H.264 可使用默认软编码器或 OpenH264,硬编码能力则取决于本机硬件和驱动环境。

NT_UINT32 codec_id = NT_MEDIA_CODEC_ID_H264;

// type: 0=软编码,1=硬编码
// encoder_id: 软编码 H.264 下 0=默认编码器,1=OpenH264;硬编码按 SDK 返回能力选择
// param1: 硬编码 GPU index,-1 表示 SDK 自动选择
publisher_api_.SetVideoEncoder(
    publisher_handle_,
    0,
    0,
    codec_id,
    0);

建议发布文档中不要笼统承诺“所有机器均支持硬编 H.265”。更准确的写法是:SDK 提供 H.264/H.265 编码能力,H.265 和硬编码支持情况与 SDK 版本、系统架构、显卡硬件及驱动环境有关,应以实际测试结果为准。

8.2 码率、质量和 GOP

常用参数包括帧率、平均码率、最大码率、质量参数、关键帧间隔、H.264 Profile 和编码速度。

publisher_api_.SetFrameRate(publisher_handle_, 15);

publisher_api_.SetVideoBitRate(publisher_handle_, 1500);       // kbps
publisher_api_.SetVideoMaxBitRate(publisher_handle_, 2000);    // kbps

// 质量值范围 [1, 50],值越小质量越好,码率越高
publisher_api_.SetVideoQualityV2(publisher_handle_, 23);

// GOP,单位为帧。例如 15fps 下设置 15,约 1 秒一个关键帧
publisher_api_.SetVideoKeyFrameInterval(publisher_handle_, 15);

// H.264 Profile:1=Baseline,2=Main,3=High
publisher_api_.SetVideoEncoderProfile(publisher_handle_, 1);

// 编码速度,具体建议以 SDK 文档和实测效果为准
publisher_api_.SetVideoEncoderSpeed(publisher_handle_, 4);

SDK 头文件中说明了两类码率控制思路:SetVideoQualityV2 + SetVideoMaxBitRate,或 SetVideoMaxBitRate + SetVideoBitRate。其中 OpenH264 场景需要重点关注固定码率相关配置。


9. 音频采集与处理

9.1 音频源选择

Windows C++ Demo 支持以下常见音频源:

音频模式 说明
无音频 纯视频推流
麦克风采集 采集本机麦克风
扬声器采集 采集系统播放声音
麦克风 + 扬声器混音 适合会议、教学、同屏讲解等场景
外部 PCM 应用层采集 PCM 后送入 SDK

上传头文件中也定义了麦克风、扬声器、麦克风扬声器混音、外部编码音频、外部 PCM 数据等音频源选项。

9.2 音频编码与音量控制

// 1=AAC,2=Speex,具体取值以 SDK 头文件和当前版本说明为准
publisher_api_.SetPublisherAudioCodecType(publisher_handle_, 1);

// 静音 / 取消静音
publisher_api_.SetMute(publisher_handle_, 1);
publisher_api_.SetMute(publisher_handle_, 0);

// 音量调节,1.0 表示原始音量
publisher_api_.SetInputAudioVolume(publisher_handle_, 0, 1.0f);

如业务场景需要,可按需启用回声消除、噪声抑制、自动增益等音频处理能力。Demo 中也包含音频输入设备枚举、麦克风/扬声器可用性判断、音量默认值和 Speex 质量参数等初始化逻辑。


10. RTMP 推流集成

10.1 基本流程

RTMP 推流的核心流程如下:

Init
  ↓
Open
  ↓
SetEventCallBack
  ↓
设置采集源和编码参数
  ↓
SetURL
  ↓
StartPublisher
  ↓
事件回调处理
  ↓
StopPublisher
  ↓
Close
  ↓
UnInit

10.2 设置推流地址并启动

bool StartRTMPPublisher(const std::string& rtmp_url)
{
    if (!OpenPublisherHandle())
        return false;

    SetCommonOptionToPublisherSDK();

    if (NT_ERC_OK != publisher_api_.SetURL(
        publisher_handle_,
        rtmp_url.c_str(),
        nullptr))
    {
        return false;
    }

    NT_UINT32 ret = publisher_api_.StartPublisher(
        publisher_handle_,
        nullptr);

    return NT_ERC_OK == ret;
}

Demo 中支持设置一路或多路 RTMP 推流地址,并在启动前调用 SetURL(),随后调用 StartPublisher()。上传代码中还可以看到 Demo 会维护推流 URL 列表,并在调用 StartPublisher() 前完成 URL 设置和用户数据队列配置。

10.3 停止推流

void StopRTMPPublisher()
{
    if (publisher_handle_ != nullptr)
    {
        publisher_api_.StopPublisher(publisher_handle_);
    }
}

如果 RTMP 推流、RTSP 流输出、录像和预览共用同一个 publisher_handle_,建议通过引用计数或状态机管理句柄生命周期。不要在仅停止 RTMP 推流时立即 Close() 句柄,否则可能影响正在运行的 RTSP 输出或录像任务。


11. 轻量级 RTSP 服务集成

轻量级 RTSP 服务模块以内置服务方式工作,典型流程如下:

OpenRtspServer
  ↓
SetRtspServerPort
  ↓
可选:SetRtspServerUserNamePassword
  ↓
可选:SetRtspServerMulticast / SetRtspServerMulticastAddress
  ↓
StartRtspServer
  ↓
SetRtspStreamName
  ↓
AddRtspStreamServer
  ↓
StartRtspStream
  ↓
通过事件回调获取 RTSP URL

SDK 头文件中明确提供了 OpenRtspServerSetRtspServerPortSetRtspServerUserNamePasswordSetRtspServerMulticastSetRtspServerMulticastAddress 等 RTSP Server 操作接口。

11.1 创建并启动 RTSP Server

NT_HANDLE rtsp_server_handle = nullptr;

bool StartRtspServer(int port)
{
    if (NT_ERC_OK != publisher_api_.OpenRtspServer(&rtsp_server_handle, 0))
        return false;

    if (rtsp_server_handle == nullptr)
        return false;

    if (NT_ERC_OK != publisher_api_.SetRtspServerPort(rtsp_server_handle, port))
    {
        publisher_api_.CloseRtspServer(rtsp_server_handle);
        rtsp_server_handle = nullptr;
        return false;
    }

    // 可选:设置用户名密码,用户名和密码建议使用英文字符
    publisher_api_.SetRtspServerUserNamePassword(
        rtsp_server_handle,
        "admin",
        "123456");

    if (NT_ERC_OK != publisher_api_.StartRtspServer(rtsp_server_handle, 0))
    {
        publisher_api_.CloseRtspServer(rtsp_server_handle);
        rtsp_server_handle = nullptr;
        return false;
    }

    return true;
}

Demo 中 RTSP Server 配置窗口支持多路服务实例配置,并可设置端口、用户名、密码、单播/组播、SSM 组播地址和会话数查询。

11.2 绑定推流实例并启动 RTSP 流

RTSP Server 启动后,需要把当前推流实例绑定到 RTSP Server,并设置流名称。

bool StartRtspStream()
{
    if (!OpenPublisherHandle())
        return false;

    SetCommonOptionToPublisherSDK();

    // URL 路径名,例如最终可能形如:rtsp://本机IP:554/live
    publisher_api_.SetRtspStreamName(publisher_handle_, "live");

    publisher_api_.AddRtspStreamServer(
        publisher_handle_,
        rtsp_server_handle,
        0);

    NT_UINT32 ret = publisher_api_.StartRtspStream(
        publisher_handle_,
        0);

    return NT_ERC_OK == ret;
}

SDK 头文件中说明,一个推流实例可以发布到多个 RTSP Server 上;SetRtspStreamName() 用于设置流名称,AddRtspStreamServer() 用于将推流实例绑定到 RTSP Server,StartRtspStream() 用于启动 RTSP 流输出。

11.3 获取 RTSP URL

RTSP 流启动后,SDK 会通过事件回调通知可播放的 RTSP URL。事件 ID 为:

NT_PB_E_EVENT_ID_RTSP_URL

事件回调中的 param5 表示 RTSP URL。上传的事件定义和 Demo 代码均体现了该事件语义。

case NT_PB_E_EVENT_ID_RTSP_URL:
{
    if (param5 != nullptr)
    {
        std::string rtsp_url = param5;
        // 将 rtsp_url 显示到 UI,或下发给局域网客户端
    }
    break;
}

11.4 查询 RTSP 客户端会话数

RTSP 服务运行过程中,可以查询当前客户端连接会话数,用于业务侧展示或运行状态监控。

NT_INT32 session_count = 0;

publisher_api_.GetRtspServerClientSessionNumbers(
    rtsp_server_handle,
    &session_count);

官网资料也明确提到轻量级 RTSP 服务支持会话连接数查询,便于上层监控服务负载和访问情况。

11.5 停止 RTSP 流与 RTSP Server

void StopRtsp()
{
    if (publisher_handle_ != nullptr)
    {
        publisher_api_.StopRtspStream(publisher_handle_);
        publisher_api_.ClearRtspStreamServer(publisher_handle_);
    }

    if (rtsp_server_handle != nullptr)
    {
        publisher_api_.StopRtspServer(rtsp_server_handle);
        publisher_api_.CloseRtspServer(rtsp_server_handle);
        rtsp_server_handle = nullptr;
    }
}

RTSP 流输出和 RTSP Server 是两个层面的资源:StopRtspStream() 停止当前推流实例的 RTSP 输出;StopRtspServer()CloseRtspServer() 用于停止并释放 RTSP Server 实例。


12. RTMP 与 RTSP 同时输出

在实际项目中,常见需求是同一路 Windows 摄像头或屏幕数据,既推送到远端 RTMP 服务器,又通过本地 RTSP URL 给局域网客户端实时播放。该场景可以复用同一个 publisher_handle_

bool StartRTMPAndRTSP()
{
    if (!OpenPublisherHandle())
        return false;

    SetCommonOptionToPublisherSDK();

    // 1. 启动 RTSP Server
    if (!StartRtspServer(554))
        return false;

    // 2. 启动 RTSP 流输出
    publisher_api_.SetRtspStreamName(publisher_handle_, "live");
    publisher_api_.AddRtspStreamServer(publisher_handle_, rtsp_server_handle, 0);

    if (NT_ERC_OK != publisher_api_.StartRtspStream(publisher_handle_, 0))
        return false;

    // 3. 启动 RTMP 推流
    publisher_api_.SetURL(
        publisher_handle_,
        "rtmp://your-server/live/stream",
        nullptr);

    if (NT_ERC_OK != publisher_api_.StartPublisher(publisher_handle_, nullptr))
        return false;

    return true;
}

上传文档中的示例也采用了类似流程:先创建并启动 RTSP Server,再设置 RTSP Stream Name、绑定 RTSP Server、启动 RTSP 流,随后再设置 RTMP URL 并启动 RTMP 推流。


13. 推流端预览

推流端预览适合在业务界面中显示当前采集或合成后的画面,便于用户确认画面内容、摄像头位置、水印叠加和窗口采集区域。

核心流程如下:

publisher_api_.SetVideoPreviewImageCallBack(
    publisher_handle_,
    NT_PB_E_IMAGE_FORMAT_RGB32,
    reinterpret_cast<NT_PVOID>(GetSafeHwnd()),
    NT_PB_SDKVideoPreviewImageHandle);

publisher_api_.StartPreview(publisher_handle_, 0, nullptr);

停止预览:

publisher_api_.StopPreview(publisher_handle_);

上传的 Demo 中,预览流程会先确保 publisher_handle_ 已创建,再设置 RGB32 图像回调并调用 StartPreview(),随后由预览窗口完成图像绘制。


14. 本地录像与截图

虽然本文重点是 RTMP 推流和轻量级 RTSP 服务,但 Windows C++ Demo 也包含录像与截图能力,可作为实际项目中的扩展功能使用。

14.1 本地录像

publisher_api_.SetRecorderDirectoryW(
    publisher_handle_,
    L"D:\\Recordings\\",
    nullptr);

publisher_api_.SetRecorderFileMaxSize(
    publisher_handle_,
    200 * 1024); // KB

NT_PB_RecorderFileNameRuler ruler = {};
ruler.file_name_prefix_ = "smartpublisher";
ruler.append_date_ = 1;
ruler.append_time_ = 1;

publisher_api_.SetRecorderFileNameRuler(
    publisher_handle_,
    &ruler);

publisher_api_.StartRecorder(
    publisher_handle_,
    nullptr);

停止录像:

publisher_api_.StopRecorder(publisher_handle_);

SDK 头文件中定义了 SetRecorderDirectoryW()SetRecorderFileMaxSize()SetRecorderFileNameRuler()StartRecorder()PauseRecorder()StopRecorder() 等录像接口。

14.2 截图

publisher_api_.CaptureImage(
    publisher_handle_,
    "D:\\snapshot.png",
    nullptr,
    NT_PB_SDKCaptureImageHandle);

截图通常是异步操作,应通过回调获取结果。发布说明中建议写清楚:截图能力依赖当前是否有可用视频帧,通常应在预览、推流、RTSP 输出或录像运行过程中调用。


15. 事件回调处理

SDK 事件回调是业务侧判断推流状态、RTSP URL、录像文件状态和异常情况的重要入口。常见事件包括:

事件 ID 说明 param5
NT_PB_E_EVENT_ID_CONNECTING 正在连接 RTMP 推流服务器 推流 URL
NT_PB_E_EVENT_ID_CONNECTED 推流连接成功 推流 URL
NT_PB_E_EVENT_ID_CONNECTION_FAILED 推流连接失败 推流 URL
NT_PB_E_EVENT_ID_DISCONNECTED 推流连接断开 推流 URL
NT_PB_E_EVENT_ID_RECORDER_START_NEW_FILE 开始写入新的录像文件 文件路径
NT_PB_E_EVENT_ID_ONE_RECORDER_FILE_FINISHED 一个录像文件完成 文件路径
NT_PB_E_EVENT_ID_CAPTURE_WINDOW_INVALID 窗口采集句柄无效
NT_PB_E_EVENT_ID_RTSP_URL RTSP URL 已生成 RTSP URL

上述事件 ID 在 SDK 头文件中有明确枚举定义,Demo 中也通过事件回调将连接状态、录像文件、RTSP URL 等信息转发到 UI 线程处理。

建议不要在 SDK 回调线程中直接操作 UI 控件。推荐通过 PostMessage() 把事件派发到主线程:

extern "C" NT_VOID NT_CALLBACK NT_PB_SDKPublisherEventHandle(
    NT_HANDLE handle,
    NT_PVOID user_data,
    NT_UINT32 event_id,
    NT_INT64 param1,
    NT_INT64 param2,
    NT_UINT64 param3,
    NT_UINT64 param4,
    NT_PCSTR param5,
    NT_PCSTR param6,
    NT_PVOID param7)
{
    HWND hwnd = reinterpret_cast<HWND>(user_data);
    if (hwnd == nullptr || !::IsWindow(hwnd))
        return;

    switch (event_id)
    {
    case NT_PB_E_EVENT_ID_CONNECTING:
    case NT_PB_E_EVENT_ID_CONNECTED:
    case NT_PB_E_EVENT_ID_CONNECTION_FAILED:
    case NT_PB_E_EVENT_ID_DISCONNECTED:
        // 建议 PostMessage 到 UI 线程后再更新状态
        break;

    case NT_PB_E_EVENT_ID_RTSP_URL:
        // param5 为可播放 RTSP URL
        break;

    default:
        break;
    }
}

Demo 中就是采用 PostMessage() 方式,把连接事件、RTSP URL、录像文件事件等从 SDK 回调线程派发到窗口线程。


16. 资源释放顺序

建议按以下顺序释放资源:

StopPublisher
  ↓
StopRtspStream
  ↓
StopRecorder
  ↓
StopPreview
  ↓
ClearRtspStreamServer
  ↓
StopRtspServer / CloseRtspServer
  ↓
Close publisher_handle
  ↓
UnInit

示例:

void ReleasePublisher()
{
    if (publisher_handle_ != nullptr)
    {
        publisher_api_.StopPublisher(publisher_handle_);
        publisher_api_.StopRtspStream(publisher_handle_);
        publisher_api_.StopRecorder(publisher_handle_);
        publisher_api_.StopPreview(publisher_handle_);
        publisher_api_.ClearRtspStreamServer(publisher_handle_);

        publisher_api_.Close(publisher_handle_);
        publisher_handle_ = nullptr;
    }

    if (rtsp_server_handle != nullptr)
    {
        publisher_api_.StopRtspServer(rtsp_server_handle);
        publisher_api_.CloseRtspServer(rtsp_server_handle);
        rtsp_server_handle = nullptr;
    }

    publisher_api_.UnInit();
}

如果业务中 RTMP、RTSP、录像、预览可能独立启停,建议不要简单地在每个“停止按钮”里直接 Close() 句柄,而应通过状态变量或引用计数判断当前是否仍有模块在使用该 publisher_handle_


17. 常见问题

17.1 StartPublisher 失败

建议检查:

  1. RTMP URL 是否合法,通常应以 rtmp:// 开头;
  2. RTMP Server 是否可访问;
  3. 防火墙、端口、DNS、网络代理是否影响连接;
  4. 是否已经成功调用 Open()
  5. 是否已经配置必要的视频源、音频源和编码参数。

17.2 RTSP URL 无法播放

建议检查:

  1. RTSP Server 是否成功启动;
  2. 端口是否被占用;
  3. Windows 防火墙是否放行对应端口;
  4. 是否调用了 SetRtspStreamName()AddRtspStreamServer()StartRtspStream()
  5. 是否通过 NT_PB_E_EVENT_ID_RTSP_URL 获取到了正确 URL;
  6. 播放器是否与当前编码格式兼容。

17.3 摄像头无画面

建议检查:

  1. 摄像头是否被其他程序占用;
  2. 摄像头 ID 是否正确;
  3. 分辨率和帧率是否为摄像头实际支持的组合;
  4. 是否调用了 SetVideoCaptureDeviceBaseParameter()
  5. 是否有安全软件拦截摄像头访问。

17.4 屏幕采集画面异常

建议检查:

  1. 屏幕裁剪区域宽高是否符合对齐要求;
  2. Windows 版本是否适合启用 DXGI;
  3. Win7 下是否需要处理 Aero 相关设置;
  4. 是否采集了分层窗口或特殊渲染窗口。

18. 集成建议

在生产项目中,建议按以下原则集成:

  1. 先跑通最小链路
    先完成“屏幕或摄像头采集 → H.264 编码 → RTMP 推流”或“屏幕/摄像头采集 → RTSP URL 输出”的最小链路,再逐步增加混音、合成、录像、截图等能力。
  2. 参数配置前置
    采集源、编码参数、图层配置、RTSP Server 绑定等操作,尽量在启动推流或启动 RTSP 流前完成。
  3. 事件回调线程隔离
    SDK 回调中不要直接操作 UI,统一通过消息机制切回主线程处理。
  4. 句柄生命周期统一管理
    RTMP 推流、RTSP 流、录像、预览可能共用同一个 publisher handle,建议使用状态机或引用计数管理,避免提前释放。
  5. 能力说明以实际版本为准
    H.265、硬编码、窗口采集、组播、外部数据接入等能力,建议在客户交付前结合 SDK 授权包、系统环境和目标硬件进行实测验证。

总结

大牛直播SDK(SmartMediaKit)Windows C++ 推流 SDK 通过统一的 C 接口函数表,为业务系统提供 RTMP 推流、轻量级 RTSP 服务、本地采集、音视频编码、视频合成、预览、录像和事件回调等能力。RTMP 推流适合对接中心服务器、CDN 或直播平台;轻量级 RTSP 服务适合在局域网内快速生成可拉流访问的实时视频服务,两者组合后,可覆盖“远端平台分发 + 本地实时查看”的典型行业需求。

对于 Windows 端实时音视频系统而言,该方案的核心价值在于:无需从零实现采集、编码、封装、推流和 RTSP 服务能力,开发者只需围绕业务场景配置采集源、编码参数和输出方式,即可快速构建稳定、低延迟、可扩展的音视频推流与局域网分发能力。


📎 CSDN官方博客:音视频牛哥-CSDN博客 

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐