一、文档概述

本文介绍如何在 HarmonyOS NEXT 工程中集成 大牛直播SDK(SmartMediaKit)RTMP直播推流模块、轻量级RTSP服务模块与录像模块,实现鸿蒙NEXT终端的屏幕同屏采集、麦克风采集、系统音采集、音视频编码、RTMP直播推流、局域网RTSP实时分发、本地录像、快照和事件回调等能力。

本文基于大牛直播SDK鸿蒙NEXT同屏推流 Demo 工程进行说明,重点覆盖以下内容:

  • APP 名称与 bundleName 修改;
  • libSmartPublisher.so 动态库拷贝;
  • ArkTS 调用 Native so 的依赖配置;
  • 屏幕采集权限申请;
  • 屏幕、麦克风、系统音联合采集;
  • 软编码、硬编码 Buffer 模式、硬编码 Surface 模式配置;
  • RTMP 推流参数配置;
  • 轻量级 RTSP 服务启动与流发布;
  • 实时录像与快照集成;
  • 横竖屏切换与分辨率热切处理;
  • 推流、RTSP、录像、快照事件回调处理;
  • 常见问题与排查建议。

二、适用场景

大牛直播SDK鸿蒙NEXT同屏推流模块适用于以下典型场景:

场景 说明
无纸化会议 将鸿蒙NEXT终端屏幕、系统声音、麦克风声音实时推送到会议服务器或局域网大屏
电子教室 教师终端同屏推送,学生端或大屏通过RTMP/RTSP实时观看
移动执法 采集执法终端屏幕内容与现场讲解音频,实时回传并本地录像留存
远程巡检 采集巡检终端屏幕、系统音和麦克风,推送到指挥中心
医疗会诊 将鸿蒙终端显示内容与语音讲解实时推送至远端会诊系统
工业可视化 将工业控制终端画面实时推送或在局域网内分发
应急指挥 将现场终端屏幕内容低延迟回传,同时通过RTSP服务供局域网多端观看

三、功能特性

大牛直播SDK鸿蒙NEXT同屏推流 Demo 主要支持以下能力:

能力分类 功能说明
屏幕采集 基于鸿蒙NEXT屏幕采集能力获取终端屏幕内容
音频采集 支持麦克风、系统音、系统音+麦克风混音、静音模式
编码能力 支持H.264/H.265,支持软编码、硬编码Buffer模式、硬编码Surface模式
RTMP推流 支持将采集后的音视频编码打包推送到RTMP服务器
RTSP服务 内置轻量级RTSP服务,无需外部部署RTSP Server即可局域网分发
实时录像 支持推流过程中同步录制MP4文件
快照能力 支持采集当前视频画面并保存为图片
事件回调 支持推流状态、RTSP URL、录像文件、快照结果等事件回调
横竖屏处理 支持横竖屏切换、分辨率热切、Surface输入重绑
低延迟能力 面向实时同屏和行业场景优化端到端延迟
多输出复用 RTMP推流、RTSP分发、本地录像可共享同一套采集编码链路

四、工程结构说明

示例工程主要目录结构如下:

SmartScreenPublisherOhos/
├── AppScope/
│   ├── app.json5
│   └── resources/base/element/string.json
│
├── entry/
│   ├── libs/
│   │   ├── arm64-v8a/
│   │   │   └── libSmartPublisher.so
│   │   └── x86_64/
│   │       └── libSmartPublisher.so
│   │
│   ├── oh-package.json5
│   │
│   └── src/main/
│       ├── cpp/types/libSmartPublisher/
│       │   ├── index.d.ts
│       │   └── oh-package.json5
│       │
│       ├── ets/
│       │   ├── entryability/
│       │   │   └── EntryAbility.ets
│       │   │
│       │   ├── media/
│       │   │   ├── NTLicenseHelper.ets
│       │   │   ├── SmartPublisherNative.ets
│       │   │   ├── SmartPublisherScreenWrapper.ets
│       │   │   ├── PublisherScreenEngine.ets
│       │   │   ├── ScreenCaptureSourceNative.ets
│       │   │   ├── ArktsScreenCaptureAdapterImpl.ets
│       │   │   ├── ScreenPublishConfigUtils.ets
│       │   │   ├── SmartPublisherEventFormatter.ets
│       │   │   └── NTSmartEventID.ets
│       │   │
│       │   └── pages/
│       │       ├── SmartScreenPublisherPage.ets
│       │       ├── RecorderManagerPage.ets
│       │       └── RecorderPlaybackPage.ets
│       │
│       ├── module.json5
│       └── resources/base/profile/main_pages.json

核心文件说明如下:

文件 说明
SmartScreenPublisherPage.ets 同屏推流主页面,负责UI、参数配置、按钮操作、状态展示
PublisherScreenEngine.ets 业务编排层,统一管理屏幕采集、推流、RTSP服务、录像、快照
SmartPublisherScreenWrapper.ets Publisher实例封装层,管理open、close、config、RTMP、RTSP、录像等状态
SmartPublisherNative.ets ArkTS Native封装层,统一调用libSmartPublisher.so导出的NAPI接口
ScreenCaptureSourceNative.ets 屏幕采集Source封装,负责调用Native屏幕采集相关接口
ArktsScreenCaptureAdapterImpl.ets 屏幕采集适配层,负责采集参数组织和采集生命周期管理
ScreenPublishConfigUtils.ets 推流配置工具类,负责配置克隆、校验、默认值处理
SmartPublisherEventFormatter.ets 事件格式化工具类,统一格式化推流、录像、快照、RTSP事件
NTSmartEventID.ets SDK事件ID定义
index.d.ts libSmartPublisher.so的ArkTS类型声明文件
entry/libs/ native动态库目录

五、推荐集成架构

推荐业务侧采用以下分层架构:

SmartScreenPublisherPage.ets
    │
    ▼
PublisherScreenEngine.ets
    │
    ▼
SmartPublisherScreenWrapper.ets
    │
    ▼
SmartPublisherNative.ets / ScreenCaptureSourceNative.ets
    │
    ▼
libSmartPublisher.so

各层职责如下:

层级 职责
页面层 UI展示、参数输入、按钮操作、日志展示、状态同步
Engine层 编排屏幕采集、RTMP推流、RTSP服务、录像、快照等业务流程
Wrapper层 管理Publisher实例、配置下发、输出状态、资源释放
Native封装层 ArkTS到NAPI接口的薄封装
Native SDK层 屏幕采集、音频采集、编码、RTMP封装、RTSP服务、录像、快照、事件回调

这种分层方式可以避免页面层直接操作大量Native接口,使业务状态更清晰,也便于后续扩展摄像头采集、GB28181设备接入、SEI数据发送、多实例推流等能力。


六、集成流程概览

鸿蒙NEXT同屏推流模块的推荐集成流程如下:

1. 修改 APP 名称与 bundleName
2. 拷贝 libSmartPublisher.so 到 entry/libs/ 指定 ABI 目录
3. 配置 entry/oh-package.json5 中的 native 依赖
4. 检查 index.d.ts 接口声明
5. 配置 module.json5 权限和后台模式
6. 初始化 SmartPublisherNative 授权信息
7. 构建 ScreenPublishConfig 推流配置
8. 申请屏幕采集权限
9. 创建 Publisher 实例
10. 创建 ScreenSource 屏幕采集源
11. 配置编码、音频、RTMP URL、RTSP服务、录像参数
12. 启动屏幕采集
13. 按需启动 RTMP 推流、轻量级 RTSP 服务、实时录像、快照
14. 通过事件回调更新页面状态和日志

七、修改 APP 名称

7.1 修改应用显示名称

应用桌面显示名称通常在以下文件中配置:

AppScope/resources/base/element/string.json

默认示例:

{
  "string": [
    {
      "name": "app_name",
      "value": "SmartPublisher"
    }
  ]
}

如果希望修改为“大牛同屏推流Demo”,可调整为:

{
  "string": [
    {
      "name": "app_name",
      "value": "大牛同屏推流Demo"
    }
  ]
}

7.2 修改 bundleName

应用包名在以下文件中配置:

AppScope/app.json5

示例:

{
  "app": {
    "bundleName": "com.smartpublisher.demo",
    "vendor": "SmartPublisher",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

正式项目中建议修改为业务自己的包名,例如:

"bundleName": "com.company.smartpublisher"

7.3 授权信息注意事项

大牛直播SDK授权校验可能与以下信息相关:

  • APP名称;
  • bundleName;
  • appIdentifier;
  • 签名指纹;
  • 授权文件或授权字符串。

示例工程中通过 NTLicenseHelper.ets 获取运行时应用信息,并传递给Native SDK。修改APP名称、包名或签名证书后,应确保授权信息与实际运行环境一致。


八、拷贝 libSmartPublisher.so

8.1 so库目录

示例工程已预留native so目录:

entry/libs/
├── arm64-v8a/
└── x86_64/

真机运行时,通常使用:

entry/libs/arm64-v8a/libSmartPublisher.so

如果需要模拟器调试,可放置:

entry/libs/x86_64/libSmartPublisher.so

注意:本示例压缩包为了降低体积,未包含真实 libSmartPublisher.so。请从大牛直播SDK正式发布包中获取对应ABI的动态库。

8.2 依赖声明

entry/oh-package.json5 中声明native so依赖:

{
  "modelVersion": "5.0.0",
  "name": "entry",
  "version": "1.0.0",
  "description": "SmartPublisher Demo Entry Module",
  "dependencies": {
    "libSmartPublisher.so": "file:./src/main/cpp/types/libSmartPublisher"
  }
}

8.3 类型声明目录

类型声明文件位于:

entry/src/main/cpp/types/libSmartPublisher/index.d.ts

ArkTS层通过如下方式导入native模块:

import smartpublisher from 'libSmartPublisher.so';

8.4 常见检查项

如果编译或运行时提示无法找到native模块,请检查:

检查项 说明
so文件是否存在 确认entry/libs/arm64-v8a/libSmartPublisher.so已放置
ABI是否匹配 真机一般使用arm64-v8a
依赖是否声明 检查entry/oh-package.json5
类型声明是否存在 检查index.d.ts
接口是否一致 index.d.ts中接口需与so导出接口一致
是否重新构建 建议Clean/Rebuild工程

九、配置应用权限与后台模式

同屏推流涉及屏幕采集、麦克风、网络传输、后台保活等能力,需要在 module.json5 中配置对应权限。

示例配置如下:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone",
      "tablet"
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "label": "$string:app_name",
        "orientation": "auto_rotation_restricted",
        "backgroundModes": [
          "audioRecording",
          "dataTransfer"
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      },
      {
        "name": "ohos.permission.MICROPHONE",
        "reason": "$string:microphone_permission_reason",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      },
      {
        "name": "ohos.permission.GET_NETWORK_INFO"
      },
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING"
      }
    ]
  }
}

权限说明如下:

权限 用途
ohos.permission.INTERNET RTMP推流、RTSP服务、网络传输
ohos.permission.MICROPHONE 麦克风音频采集
ohos.permission.GET_NETWORK_INFO 网络状态检测
ohos.permission.KEEP_BACKGROUND_RUNNING 推流、录像等长时任务后台保活

后台模式说明:

backgroundModes 用途
audioRecording 支持录音类后台任务
dataTransfer 支持网络数据传输类后台任务

如果快照需要保存到系统图库,还需要根据鸿蒙NEXT图库访问机制补充相应的媒体保存逻辑。


十、核心接口说明

10.1 Publisher生命周期接口

export function SmartPublisherOpen(
  audioOpt: number,
  videoOpt: number,
  width: number,
  height: number
): number;

export function SmartPublisherClose(handle: number): number;

接口说明:

接口 说明
SmartPublisherOpen() 创建Publisher实例,返回handle
SmartPublisherClose() 释放Publisher实例

SmartPublisherOpen() 返回值大于0表示创建成功。


10.2 事件回调接口

export function SetSmartPublisherEventCallback(
  handle: number,
  callback: PublisherEventCallback | null
): number;

用于接收RTMP推流状态、RTSP URL、录像文件、快照结果等事件。


10.3 RTMP推流接口

export function SmartPublisherSetURL(
  handle: number,
  url: string
): number;

export function SmartPublisherStartPublisher(
  handle: number
): number;

export function SmartPublisherStopPublisher(
  handle: number
): number;

接口说明:

接口 说明
SmartPublisherSetURL() 设置RTMP推流地址
SmartPublisherStartPublisher() 启动RTMP推流
SmartPublisherStopPublisher() 停止RTMP推流

10.4 轻量级RTSP服务接口

export function InitRtspServer(reserve: number): number;

export function OpenRtspServer(reserve: number): number;

export function SetRtspServerPort(
  serverHandle: number,
  port: number
): number;

export function StartRtspServer(
  serverHandle: number,
  reserve: number
): number;

export function StopRtspServer(
  serverHandle: number
): number;

流发布接口:

export function SetRtspStreamName(
  handle: number,
  name: string
): number;

export function AddRtspStreamServer(
  handle: number,
  serverHandle: number,
  reserve: number
): number;

export function StartRtspStream(
  handle: number,
  reserve: number
): number;

export function StopRtspStream(
  handle: number
): number;

10.5 屏幕采集接口

export function SmartPublisherCreateScreenSource(
  width: number,
  height: number,
  sampleRate: number,
  channels: number,
  enableInnerAudio: boolean,
  enableMic: boolean
): number;

export function SmartPublisherStartScreenSource(
  handle: number
): number;

export function SmartPublisherStartScreenSourceWithSurface(
  handle: number,
  surfaceId: string
): number;

export function SmartPublisherStopScreenSource(
  handle: number
): number;

export function SmartPublisherResizeScreenSourceCanvas(
  handle: number,
  width: number,
  height: number
): number;

说明:

接口 说明
SmartPublisherCreateScreenSource() 创建屏幕采集源
SmartPublisherStartScreenSource() 启动Buffer模式屏幕采集
SmartPublisherStartScreenSourceWithSurface() 启动Surface模式屏幕采集
SmartPublisherResizeScreenSourceCanvas() 调整屏幕采集Canvas尺寸

10.6 录像接口

export function SmartPublisherCreateFileDirectory(
  path: string
): number;

export function SmartPublisherSetRecorderDirectory(
  handle: number,
  path: string
): number;

export function SmartPublisherSetRecorderFileMaxSize(
  handle: number,
  sizeMB: number
): number;

export function SmartPublisherSetRecorderVideo(
  handle: number,
  enable: number
): number;

export function SmartPublisherSetRecorderAudio(
  handle: number,
  enable: number
): number;

export function SmartPublisherStartRecorder(
  handle: number
): number;

export function SmartPublisherStopRecorder(
  handle: number
): number;

10.7 快照接口

export function SmartPublisherSaveCurImage(
  handle: number,
  fileName: string
): number;

export function CaptureImage(
  handle: number,
  format: number,
  quality: number,
  fileName: string,
  userData: string
): number;

参数说明:

参数 说明
format 图片格式,例如JPEG/PNG
quality 图片质量,建议范围1–100
fileName 图片保存路径
userData 业务自定义透传字段

十一、屏幕采集集成

11.1 功能说明

屏幕采集用于获取鸿蒙NEXT终端当前屏幕画面,并将其送入SDK编码链路。

推荐业务流程:

用户点击申请屏幕权限
    ↓
构建ScreenCaptureStartOptions
    ↓
创建ScreenSource
    ↓
启动屏幕采集
    ↓
根据编码模式选择Buffer输入或Surface输入
    ↓
进入编码、推流、RTSP服务、录像链路

11.2 采集参数

典型参数包括:

export interface ScreenCaptureStartOptions {
  width: number;
  height: number;
  fps: number;
  enableMic: boolean;
  enableInnerAudio: boolean;
  showCursor: boolean;
  canvasRotation: boolean;
  useEncoderSurface: boolean;
}

参数说明:

参数 说明
width 采集宽度
height 采集高度
fps 采集帧率
enableMic 是否采集麦克风
enableInnerAudio 是否采集系统音
showCursor 是否显示鼠标指针
canvasRotation 是否启用Canvas旋转
useEncoderSurface 是否使用编码器Surface输入

11.3 Buffer模式

Buffer模式下,屏幕数据回调到ArkTS层,再通过Native接口投递给SDK:

this.nativePublisher.postLayerImageRGBX8888(
  0,
  0,
  0,
  frame,
  0,
  rowStride,
  width,
  height,
  false,
  false,
  0,
  0,
  0,
  0
);

适用场景:

  • 需要叠加图层;
  • 需要在上层控制图像输入;
  • 需要兼容非Surface编码路径;
  • 需要做图像处理或业务扩展。

11.4 Surface模式

Surface模式下,屏幕采集数据直接写入编码器输入Surface:

OH_AVScreenCapture
    ↓
Encoder Input Surface
    ↓
libSmartPublisher.so
    ↓
RTMP / RTSP / Recorder

Surface模式减少了ArkTS层视频帧回调和内存拷贝,更适合低延迟同屏推流场景。

HarmonyOS 鸿蒙NEXT无纸化同屏时延测试


十二、音频采集与混音集成

12.1 音频模式

示例工程支持以下音频模式:

模式 说明
静音 不采集、不输出音频
仅麦克风 只采集麦克风音频
仅系统音 只采集系统播放声音
系统音 + 麦克风 同时采集系统音和麦克风,并进行混音

对应枚举:

export enum ScreenAudioOutputType {
  NONE = 0,
  MIC = 1,
  SYSTEM = 2,
  SYSTEM_AND_MIC = 3
}

12.2 系统音投递

系统音通常切成10ms PCM帧后投递:

this.innerFramer.push(chunk.buffer, (frame, sr, ch, pcs) => {
  this.publisher.postSystemAudioPCM(frame, sr, ch, pcs);
});

12.3 麦克风投递

麦克风音频同样切成10ms PCM帧后投递:

this.micFramer.push(chunk.buffer, (frame, sr, ch, pcs) => {
  this.publisher.postMicAudioPCM(frame, sr, ch, pcs);
});

12.4 系统音+麦克风混音

当选择“系统音 + 麦克风”时,建议启用SDK混音能力:

this.nativePublisher.setAudioMix(true);

麦克风音频作为第二路音频输入:

this.nativePublisher.onMixPCMData(
  1,
  pcm10ms,
  0,
  pcm10ms.byteLength,
  sampleRate,
  channels,
  perChannelSamples
);

这样可以实现屏幕内容声音与用户讲解声音同步进入RTMP推流、RTSP分发和本地录像。


十三、编码模式配置

示例工程提供以下编码模式:

编码模式 说明
软编H.264 兼容性好,适合基础功能验证
硬编H.264 使用系统硬编码能力,性能更优
硬编H.265 码率效率更高,适合高分辨率场景
硬编H.264(Surface) 屏幕数据直写编码器Surface,减少拷贝
硬编H.265(Surface) H.265 + Surface输入,适合高效低延迟同屏

示例配置:

private readonly encoderPresets: EncoderEntry[] = [
  new EncoderEntry('软编 H.264', PublisherVideoEncoderType.SOFT_H264, false),
  new EncoderEntry('硬编 H.264', PublisherVideoEncoderType.HW_H264, false),
  new EncoderEntry('硬编 H.265', PublisherVideoEncoderType.HW_H265, false),
  new EncoderEntry('硬编 H.264(Surface)', PublisherVideoEncoderType.HW_H264, true),
  new EncoderEntry('硬编 H.265(Surface)', PublisherVideoEncoderType.HW_H265, true)
];

编码模式选择建议:

场景 推荐模式
兼容性验证 软编H.264
普通同屏推流 硬编H.264
高分辨率推流 硬编H.265
低延迟正式场景 硬编H.264(Surface)
高分辨率低码率场景 硬编H.265(Surface)

十四、RTMP推流集成

14.1 功能说明

RTMP推流用于将屏幕、系统音、麦克风音频编码后,通过RTMP协议推送到直播服务器。

典型流程如下:

构建ScreenPublishConfig
    ↓
Engine.prepare(config)
    ↓
SmartPublisherOpen()
    ↓
设置编码参数、音频参数、URL、FPS、GOP
    ↓
启动屏幕采集
    ↓
SmartPublisherStartPublisher()
    ↓
连接RTMP服务器
    ↓
持续发送音视频数据

14.2 RTMP URL示例

rtmp://your-server/live/stream1

14.3 启动推流

页面层通常调用:

const ok: boolean = await this.engine.startPublish(config);

Engine层调用:

async startPublish(config: ScreenPublishConfig): Promise<boolean> {
  const next: ScreenPublishConfig = cloneScreenConfig(config);
  next.enableRecorder = false;

  if (!await this.prepare(next)) {
    return false;
  }

  const ok: boolean = this.publisher.startPublisherDirect();
  return ok;
}

Wrapper层最终调用:

this.nativePublisher.startPublisher();

对应Native接口:

SmartPublisherStartPublisher(handle);

14.4 停止推流

SmartPublisherStopPublisher(handle);

停止RTMP推流时,不建议立即释放整个Publisher实例。因为RTSP服务、录像等模块可能仍在运行。推荐在RTMP、RTSP、录像全部停止后,再统一释放采集和Publisher资源。

鸿蒙NEXT无纸化同屏端到端时延测试


十五、轻量级RTSP服务集成

15.1 功能说明

轻量级RTSP服务用于在鸿蒙NEXT终端本地启动一个RTSP Server,将当前采集编码后的音视频流在局域网内分发给其他播放器。

它的优势是:

  • 无需额外部署RTSP Server;
  • 终端自身即可作为RTSP服务端;
  • 适合局域网大屏、内网播放器、会议终端拉流;
  • 可与RTMP推流、本地录像共用同一套采集编码链路。

15.2 服务启动流程

InitRtspServer()
    ↓
OpenRtspServer()
    ↓
SetRtspServerPort(port)
    ↓
StartRtspServer()
    ↓
SetRtspStreamName(streamName)
    ↓
AddRtspStreamServer(serverHandle)
    ↓
StartRtspStream()
    ↓
生成RTSP播放URL

15.3 典型配置

const port: number = 38554;
const streamName: string = 'stream1';

生成的播放地址通常类似:

rtsp://设备IP:38554/stream1

15.4 启动RTSP服务

const ok: boolean = this.engine.startRtspService(port);

启动RTSP流发布:

const ok: boolean = await this.engine.startRtspStream(config, streamName);

当SDK生成RTSP播放URL后,会通过事件回调返回给页面层,页面可在日志或状态区域显示该URL。

鸿蒙NEXT无纸化同屏之轻量级RTSP服务器端到端时延测试


十六、实时录像集成

16.1 功能说明

实时录像用于在同屏采集、RTMP推流或RTSP分发过程中,同步将音视频数据录制为本地MP4文件。

典型应用场景:

  • 会议留档;
  • 执法取证;
  • 巡检过程记录;
  • 远程协作过程回溯;
  • 现场问题复盘。

16.2 录像目录

推荐将录像文件保存到应用沙盒目录,例如:

/data/storage/el2/base/files/smartpublisher_record

16.3 录像参数

典型录像参数包括:

recorderDir: string;
recordFileMaxSizeMB: number;
recordVideoEnabled: boolean;
recordAudioEnabled: boolean;

16.4 启动录像

const ok: boolean = await this.engine.startRecorder(config);

底层调用流程:

SmartPublisherCreateFileDirectory()
SmartPublisherSetRecorderDirectory()
SmartPublisherSetRecorderFileMaxSize()
SmartPublisherSetRecorderVideo()
SmartPublisherSetRecorderAudio()
SmartPublisherStartRecorder()

16.5 停止录像

SmartPublisherStopRecorder(handle);

16.6 录像事件

录像相关事件包括:

事件 说明
RECORDER_START_NEW_FILE 开始新的录像文件
RECORDER_FILE_FINISHED 单个录像文件完成

建议在页面日志中输出完整录像文件路径,便于测试和文件管理。


十七、快照集成

17.1 功能说明

快照用于在推流或采集过程中抓取当前视频画面,并保存为图片文件。

典型应用场景:

  • 会议关键画面保存;
  • 执法现场截图;
  • 巡检异常画面留存;
  • 工业设备画面取证;
  • 远程协作过程记录。

17.2 快照接口

SmartPublisherSaveCurImage(handle, fileName);

CaptureImage(handle, format, quality, fileName, userData);

17.3 参数说明

参数 说明
format 图片格式,例如JPEG/PNG
quality 图片质量,建议1–100
fileName 图片保存路径
userData 业务自定义字段

17.4 使用建议

快照建议先保存到应用沙盒目录,再根据业务需要保存到系统图库。这样可以避免图库授权失败影响基础快照功能,也便于日志排查和文件管理。


十八、事件回调处理

18.1 事件类型

推流端常见事件包括:

事件 说明
PUBLISHER_STARTED 推流启动
PUBLISHER_CONNECTING RTMP连接中
PUBLISHER_CONNECTED RTMP连接成功
PUBLISHER_CONNECTION_FAILED RTMP连接失败
PUBLISHER_DISCONNECTED RTMP连接断开
PUBLISHER_STOP 推流停止
PUBLISHER_RTSP_URL RTSP播放URL生成
RECORDER_START_NEW_FILE 开始新的录像文件
RECORDER_FILE_FINISHED 单个录像文件完成
CAPTURE_IMAGE 快照结果

18.2 事件处理建议

建议遵循以下原则:

  • 事件回调只做轻量级状态更新;
  • 文件操作、图库保存等耗时任务放到异步逻辑;
  • RTSP URL、录像文件路径、快照路径建议完整输出;
  • 连接失败、断开等事件建议记录最近错误;
  • 事件格式化逻辑建议集中维护在 SmartPublisherEventFormatter.ets 中。

示例:

case EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
  this.rtspPlaybackUrl = strParam;
  this.appendLog(`RTSP播放地址: ${strParam}`);
  break;

case EVENT_DANIULIVE_ERC_PUBLISHER_RECORDER_START_NEW_FILE:
  this.appendLog(`开始新的录像文件: ${strParam}`);
  break;

case EVENT_DANIULIVE_ERC_PUBLISHER_ONE_RECORDER_FILE_FINISHED:
  this.appendLog(`录像文件完成: ${strParam}`);
  break;

十九、多输出链路管理

19.1 功能说明

同屏推流端通常不是单一输出,而是可能同时运行:

屏幕采集
    ↓
编码打包
    ├── RTMP推流
    ├── 轻量级RTSP服务
    └── 本地录像

推荐将RTMP、RTSP、录像都挂在同一个Publisher实例下,共享同一套采集、编码和封装链路。

19.2 状态管理建议

建议维护以下状态:

状态 说明
isPrepared 是否已完成屏幕采集准备
isPublishing 是否正在RTMP推流
isRtspServiceRunning RTSP服务是否运行
isRtspStreamRunning RTSP流是否正在发布
isRecording 是否正在录像
isSurfaceInputMode 是否使用Surface输入编码

19.3 资源释放原则

推荐资源释放策略:

停止RTMP推流
    ↓
检查RTSP是否仍在运行
    ↓
检查录像是否仍在运行
    ↓
如仍有输出运行,则保留Publisher实例
    ↓
RTMP、RTSP、录像全部停止后,再释放采集和Publisher资源

这样可以避免停止某一路输出时影响其他正在运行的链路。


二十、常见问题

20.1 SmartPublisherOpen() 返回0

请检查:

  • libSmartPublisher.so 是否已放到 entry/libs/arm64-v8a/
  • ABI是否与设备匹配;
  • entry/oh-package.json5 是否声明依赖;
  • index.d.ts 是否存在;
  • APP名称、bundleName、签名是否与授权匹配;
  • 授权初始化逻辑是否正常执行。

20.2 编译时报找不到 libSmartPublisher.so

请检查:

"dependencies": {
  "libSmartPublisher.so": "file:./src/main/cpp/types/libSmartPublisher"
}

以及:

entry/src/main/cpp/types/libSmartPublisher/index.d.ts

同时确认DevEco Studio已重新同步和构建工程。


20.3 屏幕采集权限没有弹出

建议检查:

  • 是否调用了屏幕采集准备流程;
  • 是否使用了正确的ScreenSource创建接口;
  • 当前Ability是否处于前台;
  • 用户是否曾拒绝授权;
  • 横竖屏切换时是否错误地重复申请权限。

20.4 RTMP推流连接失败

建议检查:

  • RTMP URL是否正确;
  • 手机与RTMP服务器网络是否互通;
  • RTMP服务器端口是否开放;
  • streamName是否正确;
  • 是否收到CONNECTINGCONNECTEDCONNECTION_FAILED事件;
  • 推流服务器是否支持当前音视频编码格式。

20.5 RTSP服务启动成功但客户端拉不到流

建议检查:

  • RTSP服务是否启动成功;
  • RTSP流是否已经发布;
  • 是否收到RTSP URL事件;
  • 手机IP是否正确;
  • 客户端与手机是否在同一局域网;
  • RTSP端口是否被网络策略拦截;
  • 客户端拉流地址是否完整。

20.6 录像没有生成文件

建议检查:

  • 录像目录是否创建成功;
  • 是否设置了RecorderDirectory;
  • 是否设置了录像音视频开关;
  • 是否调用了StartRecorder;
  • 是否有有效音视频数据输入;
  • 是否收到RECORDER_START_NEW_FILE事件。

20.7 快照失败

建议检查:

  • 当前是否已有视频帧输入;
  • Publisher实例是否有效;
  • 快照保存路径是否可写;
  • 图片格式参数是否正确;
  • 是否收到CAPTURE_IMAGE事件。

二十一、集成建议与最佳实践

21.1 推流流程建议

推荐流程:

申请屏幕权限
    ↓
创建Publisher实例
    ↓
创建ScreenSource
    ↓
配置编码、音频、URL、RTSP、录像参数
    ↓
启动屏幕采集
    ↓
按需启动RTMP / RTSP / Recorder

不建议在未完成屏幕采集准备前直接启动RTMP推流或录像。


21.2 权限申请建议

建议将“申请屏幕权限”和“开始推流”拆分为两个动作:

申请屏幕权限:只负责创建和准备采集链路
开始推流:只负责启动RTMP输出

这样可以避免每次启动RTMP、RTSP或录像时都重复弹出屏幕采集权限,提高用户体验和工程稳定性。


21.3 录像建议

推流中启动录像时,只下发录像相关参数,不建议重复下发完整编码参数。

推荐:

采集编码链路保持不变
    ↓
设置录像目录
    ↓
设置录像文件大小
    ↓
设置录像音视频开关
    ↓
启动录像

这样可以减少推流闪断、编码器重建和状态错乱风险。


21.4 RTSP服务建议

RTSP服务建议独立管理:

先启动RTSP Server
再将当前Publisher流发布到RTSP Server
最后通过事件回调展示RTSP URL

业务上可将RTSP Server作为局域网分发能力,将RTMP作为公网或服务器侧直播能力,两者并行互不影响。


21.5 Surface模式建议

正式低延迟同屏场景优先考虑硬编码Surface模式。

优势包括:

  • 减少视频帧在ArkTS层回调;
  • 减少内存拷贝;
  • 降低CPU占用;
  • 更适合高分辨率屏幕采集;
  • 更适合低延迟推流。

但Surface模式对横竖屏切换、Surface生命周期和编码器尺寸一致性要求更高,需要做好分辨率热切和关键帧请求。


21.6 事件日志建议

建议保留以下日志:

  • Publisher open结果;
  • ScreenSource创建结果;
  • 屏幕采集启动结果;
  • RTMP连接状态;
  • RTSP服务端口;
  • RTSP播放URL;
  • 录像文件路径;
  • 快照文件路径;
  • 横竖屏切换和分辨率变化;
  • 编码模式和分辨率参数。

音视频SDK集成中,日志是定位现场问题的重要依据。


二十二、总结

大牛直播SDK(SmartMediaKit)鸿蒙NEXT同屏推流方案,面向实时屏幕采集、低延迟直播推流、局域网RTSP分发、本地录像和快照等场景,提供了一套较完整的端侧音视频采集与发布能力。

它通过:

屏幕采集
    ↓
音频采集与混音
    ↓
软/硬编码
    ↓
RTMP推流 / RTSP分发 / 本地录像 / 快照

构建出一条适合鸿蒙NEXT行业应用落地的实时音视频链路。

从工程集成角度看,推荐采用:

页面UI层
    ↓
Engine业务编排层
    ↓
Publisher Wrapper封装层
    ↓
ArkTS Native封装层
    ↓
libSmartPublisher.so Native内核

这种方式可以让页面逻辑保持清晰,让采集、推流、RTSP、录像、快照等模块具备良好的解耦性和可维护性。

对于无纸化会议、移动执法、远程巡检、医疗会诊、工业可视化、电子教室、应急指挥等场景,该方案不仅可以完成RTMP公网推流,也可以通过轻量级RTSP服务实现局域网低延迟分发,并支持本地录像留档和关键画面快照,适合作为鸿蒙NEXT实时音视频应用的基础能力模块。


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

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐