HarmonyOS鸿蒙Next中OH_VideoEncoder surface输入模式下低延迟配置与sync mode均开启后,编码器内部仍稳定约80ms延迟,是否有降低surface pipeline缓冲的方法

HarmonyOS鸿蒙Next中OH_VideoEncoder surface输入模式下低延迟配置与sync mode均开启后,编码器内部仍稳定约80ms延迟,是否有降低surface pipeline缓冲的方法

问题背景

我们在做鸿蒙端屏幕投屏/录屏编码场景,目标是实时投屏,期望尽量降低画面更新延迟。

当前主要链路如下:

OH_AVScreenCapture
  -> OH_AVScreenCapture_StartScreenCaptureWithSurface
  -> NativeImage / GLES scaler
  -> OH_VideoEncoder_GetSurface() 得到的 encoder input surface
  -> H.264 编码输出
  -> 网络发送

现在遇到的问题是:在 surface 输入模式下,帧已经提交到 encoder input surface 之后,到编码器输出 buffer ready 之间存在稳定约 70-90ms 的延迟。这个延迟看起来不是 GLES 渲染、业务线程转发、网络发送造成的,而更像编码器 surface pipeline 内部缓存了一帧或多帧。

环境信息

  • 设备 1:HUAWEI Mate 60
  • 设备 2:HUAWEI Mate 60 Pro
  • 编码格式:H.264 / AVC
  • 输入模式:surface input
  • 分辨率示例:976x2160
  • 业务场景:实时屏幕投屏 / 录屏编码

已配置的编码参数

目前已经尝试设置低延迟相关参数:

OH_MD_KEY_FRAME_RATE
OH_MD_KEY_PIXEL_FORMAT = AV_PIXEL_FORMAT_SURFACE_FORMAT
OH_MD_KEY_BITRATE
OH_MD_KEY_VIDEO_ENCODE_BITRATE_MODE
OH_MD_KEY_PROFILE = AVC_PROFILE_BASELINE
OH_MD_KEY_I_FRAME_INTERVAL

OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY = 1
OH_MD_KEY_VIDEO_ENCODER_ENABLE_TEMPORAL_SCALABILITY = 0
OH_MD_KEY_VIDEO_ENCODER_ENABLE_B_FRAME = 0
OH_MD_KEY_VIDEO_ENCODER_ENABLE_PTS_BASED_RATECONTROL = 1

也尝试过 sync mode:

OH_MD_KEY_ENABLE_SYNC_MODE = 1
OH_VideoEncoder_QueryOutputBuffer(...)
OH_VideoEncoder_GetOutputBuffer(...)

延迟统计口径

我们在每帧上记录了几个阶段耗时:

sourceToEncoderInputMs: 采集帧可用到提交 encoder input surface
sourceToPacingMs: 采集帧可用到进入 pacing
pacingWaitMs: pacing 等待耗时
renderToSwapMs: GLES 渲染到 swap 的耗时
swapToEncoderInputMs: swap 后到记录 encoder input submitted 的耗时
encoderPipelineMs: encoder input submitted 到 encoder output buffer ready 的耗时
encoderOutputToWorkerMs: output ready 到业务线程处理的耗时
workerToSharedSinkMs: 编码输出进入业务 sink 的耗时
packetizeMs: 分包耗时
sendQueueWaitMs: 网络发送队列等待耗时
sendElapsedMs: 实际发送耗时

这里最关注的是:

encoderPipelineMs = encoder input submitted -> encoder output buffer ready

日志现象

设备 1:callback 输出模式

统计结果大致如下:

frames=698
encoderPipelineMs count=697 avg=74.0 min=64 p50=73 p90=80 p95=82 max=97
swapToEncoderInputMs count=697 avg=3.9 min=0 p50=4 p90=6 p95=7 max=24
sendQueueWaitMs count=698 avg=1.2 min=0 p50=1 p90=3 p95=6 max=17
sendElapsedMs count=698 avg=0.0 min=0 p50=0 p90=0 p95=0 max=0

可以看到 encoderPipelineMs 稳定在 70-80ms 左右,而提交 encoder surface 前后的耗时、发送队列耗时和实际发送耗时都很低。

设备 2:sync mode 确认启用

日志确认 sync mode 已经启用:

video encoder latency test config: singleInFlight=0, syncMode=1, dataBufferInput=0, frameDuplication=0, maxInputBuffers=0, maxOutputBuffers=0
video encoder sync-mode options: requested=1, keyAvailable=1, queryOutputAvailable=1, getOutputAvailable=1, enabled=1
video encoder sync-mode configured: setOn=1, queryTimeoutUs=50000
video encoder sync output queried: ...

过滤掉一次 1071ms 离群值后,encoderPipelineMs 仍然没有明显下降:

encoderPipelineMs count=72 avg=82.2 min=15 p50=83 p90=87 p95=89 max=93
sourceToEncoderInputMs count=73 avg=5.2 min=3 p50=5 p90=7 p95=8 max=13
swapToEncoderInputMs count=73 avg=1.9 min=0 p50=2 p90=3 p95=4 max=5
encoderOutputToWorkerMs count=73 avg=2.6 min=0 p50=0 p90=2 p95=14 max=45
sendElapsedMs count=74 avg=0.0 min=0 p50=0 p90=0 p95=0 max=0

也就是说,sync mode 确实让 output ready 后的取帧和线程转发更快了,但没有降低 encoder input surface -> output buffer ready 这段内部延迟。

已尝试和排查过的方案

  1. 开启低延迟参数:OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY = 1
  2. 禁用 B 帧:OH_MD_KEY_VIDEO_ENCODER_ENABLE_B_FRAME = 0
  3. 使用 H.264 baseline profile。
  4. 禁用 temporal scalability。
  5. 开启 PTS based rate control。
  6. 尝试 sync mode,用 QueryOutputBuffer/GetOutputBuffer 主动 drain 输出。
  7. 上游限制 in-flight frame,避免应用层继续堆旧帧。
  8. 排查发送队列和网络发送耗时,确认不是网络层造成。

当前判断

从日志看,主要延迟集中在编码器内部:

encoder input surface submitted -> encoder output buffer ready

sync mode 只改变 output buffer 获取方式,能降低 output ready 之后的取帧/分发等待,但没有改变 surface 输入到编码输出 ready 的内部 pipeline latency。

因此目前怀疑 surface input 模式下,硬编内部可能存在固定 pipeline 缓冲深度,或者低延迟参数没有完全影响 surface input 的内部排队策略。

想请教的问题

  1. OH_VideoEncoder 在 surface input 模式下,是否存在固定的内部 pipeline 缓冲深度?例如必须缓存 1-2 帧后才输出?
  2. OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY 对 surface input 模式是否一定生效?是否有额外前置条件?
  3. sync mode 是否只影响 output buffer 获取方式,而不改变编码器内部输入到输出的排队深度?
  4. 是否有官方推荐的参数组合,用于实时投屏/录屏编码低延迟场景?
  5. OH_MD_MAX_INPUT_BUFFER_COUNT / OH_MD_MAX_OUTPUT_BUFFER_COUNT 是否支持用于降低 surface 模式下的内部缓冲?如果支持,推荐值是多少?
  6. 如果目标是实时投屏,是否建议从 surface input 改为 data buffer input?两者在编码延迟上是否有已知差异?
  7. 有没有方法可以强制 encoder 在 surface 输入模式下“收到一帧尽快输出一帧”,避免稳定 80ms 左右的 pipeline latency?

期望

希望确认这是否是当前鸿蒙硬编 surface 模式的预期行为,还是我们的参数使用方式不完整。如果有推荐的低延迟配置、设备能力查询方式或最小复现写法,也希望能提供建议。


更多关于HarmonyOS鸿蒙Next中OH_VideoEncoder surface输入模式下低延迟配置与sync mode均开启后,编码器内部仍稳定约80ms延迟,是否有降低surface pipeline缓冲的方法的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

开发者您好,为了更精确的确认您的问题,辛苦您提供下可以复现您问题的demo代码,包括日志打印位置,以便我们进一步定位分析。

更多关于HarmonyOS鸿蒙Next中OH_VideoEncoder surface输入模式下低延迟配置与sync mode均开启后,编码器内部仍稳定约80ms延迟,是否有降低surface pipeline缓冲的方法的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


补充一个更偏验证的思路:从公开 C API 看,OH_VideoEncoder_GetSurface() 返回的 input surface 目前没有看到“把 Surface/BufferQueue 队列深度强制改成 1”的独立接口。OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY 和 OH_MD_KEY_ENABLE_SYNC_MODE 都是 Configure 阶段的可选键,更像是编码器工作模式/低时延提示;它们不一定能绕过硬编内部的重排、参考帧或 surface 消费侧缓存。

建议先做一个 A/B 实验:在 Configure 前把最大输入/输出 buffer 数也压低,再看返回值和延迟是否变化。如果返回成功但 encoderPipelineMs 仍稳定 70-90ms,基本可以判断这条 surface input 路径没有被应用侧公开接口继续压队列。

#include <multimedia/player_framework/native_avformat.h>
#include <multimedia/player_framework/native_avcodec_videoencoder.h>

OH_AVFormat *fmt = OH_AVFormat_Create();
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_WIDTH, width);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_HEIGHT, height);
OH_AVFormat_SetDoubleValue(fmt, OH_MD_KEY_FRAME_RATE, fps);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_PIXEL_FORMAT, AV_PIXEL_FORMAT_SURFACE_FORMAT);
OH_AVFormat_SetLongValue(fmt, OH_MD_KEY_BITRATE, bitrate);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_PROFILE, AVC_PROFILE_BASELINE);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_I_FRAME_INTERVAL, 1);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY, 1);
OH_AVFormat_SetIntValue(fmt, OH_MD_KEY_ENABLE_SYNC_MODE, 1);
OH_AVFormat_SetIntValue(fmt, OH_MD_MAX_INPUT_BUFFER_COUNT, 2);   // 可尝试 1/2 做对照
OH_AVFormat_SetIntValue(fmt, OH_MD_MAX_OUTPUT_BUFFER_COUNT, 2);

int32_t ret = OH_VideoEncoder_Configure(encoder, fmt);

定位时不要只看业务时间戳,建议抓 Profiler/Trace 里的 BufferQueue 流转:RequestBuffer、FlushBuffer、AcquireBuffer、ReleaseBuffer,重点看同一个 queueId 下 sequence 是否已经堆了多帧。再把 30fps/60fps、976x2160/较低分辨率、surface input/buffer input 三组做交叉对照:如果延迟按“帧数”缩放,多半是队列;如果主要按分辨率/码率变化,多半是硬编处理时间。

实时投屏场景的工程规避通常是:编码器积压时不要继续把旧帧 swap 到 input surface,只保留最新帧;或者改 buffer input 模式,用 OH_AVCodecOnNeedInputBuffer/OH_AVCodecOnNewOutputBuffer 自己做帧节流。参考:VideoEncoder GetSurface:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-avcodec-videoencoder-h#oh_videoencoder_getsurface,CodecBase 键值说明:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/capi-native-avcodec-base-h,视频编码指南:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/video-encoding

surface input 模式下的 70-90ms 不一定都能通过参数消掉,OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY 和 sync mode 更像低时延提示与工作模式配置,不等于公开了 surface pipeline 的全部队列深度控制。

建议分段验证:1. 用时间戳分别打在 ScreenCapture 输出、GLES 提交、queue 到 encoder surface、回调 output buffer 四个点,先确认延迟确实集中在编码器输入后;2. 查询当前 H.264 encoder 对 low latency、B frame、分层编码等特性的支持情况,不支持的键可能配置了也不生效;3. 关闭 B 帧、缩短 GOP、降低分辨率或帧率做对照,确认是不是硬编内部重排/缓存;4. 如果业务能接受,测试 buffer input 路径作为对照,它更容易观察每帧入队节奏。

如果所有低延迟参数都已生效,且不同设备都稳定多出 2-3 帧延迟,那可能是当前硬件编码 surface 链路的下限,需要带最小 Demo 和分段耗时数据反馈。

请提供需要转换的HTML内容。

支持,

在OH_VideoEncoder surface输入模式下,即使开启低延迟与同步模式,surface pipeline仍存在固有缓冲(通常2-3帧)。可通过以下方法降低缓冲:使用OH_NativeBuffer的setParameter设置OH_NATIVEBUFFER_LOW_LATENCY标志;调整Surface的BufferQueue大小为1;或在编码器配置中将OH_MD_KEY_VIDEO_ENCODER_LATENCY设为0。若仍稳定80ms,则可能是硬件编码器的最小缓冲限制导致。

在HarmonyOS Next中,OH_VideoEncoder的surface输入模式确实存在内部管道缓冲,当前约80ms的延迟是该模式的预期行为,主要受硬件编码器固定管道深度、帧参考关系和驱动调度影响。你已启用的OH_MD_KEY_VIDEO_ENABLE_LOW_LATENCY和sync mode主要优化码控策略和输出取帧方式,不直接降低surface到输出的排队延迟,sync mode仅绕过输出回调线程分发,不改变编码器内部缓冲。surface模式为平衡吞吐量和延迟,会缓存少数帧(如参考帧或预处理帧),无法强制“一帧进一帧出”,H.264 baseline和B帧禁用虽简化编码,但硬件管道的最小缓冲仍存续。

若需更低延迟,可尝试调节OH_MD_MAX_INPUT_BUFFER_COUNT为1或2来限制输入排队,并设置OH_MD_MAX_OUTPUT_BUFFER_COUNT为更小值(如1或0),但surface模式下这些参数影响有限。若要求极致实时性,data buffer输入模式通常管道缓冲更浅,延迟波动更小,但需自行管理buffer提交和渲染同步。当前阶段surface模式的internal pipeline latency在70-90ms区间属于硬件特性范畴,暂无公开接口强制消除,建议基于业务容忍度进行权衡。

回到顶部