目录

智能流畅倍速解码

能力简介

从API版本26.0.0开始,新增支持智能流畅倍速解码能力,通过结合硬件解码能力与人因感知模型实现系统级解码性能优化。

在传统多媒体架构中,开启高倍速播放会导致视频理论帧率成倍增加(如60fps视频在3.0x下需每秒处理180帧),并带来以下问题。

  1. 移动端设备的视频送显帧率通常受限于整机功耗管控(常为60fps),远低于高倍速下的理论帧率。此外,在高速动态画面下,受限于人眼的视觉暂留效应与动态视觉敏感度下降,强行解码并渲染超出分辨能力的微小运动帧,会产生无效的算力消耗。
  2. 传统架构中的倍速丢帧通常在应用层的渲染端被动触发,此时多余帧的解码算力已经消耗。若应用层试图在解码前主动进行内容感知,则需引入高耗能的像素级计算(如光流分析),导致整体功耗反而增加。

使用智能流畅倍速解码能力,系统无需进行复杂的像素级图像分析,而是直接利用硬件解码器输出的运动矢量(Motion Vectors,简称MV)以及视频码流的时域分层特征。实现在解码前精准剔除视觉感知权重较低的非关键帧,避免无效的解码计算。该能力在降低解码与渲染负载、有效控制设备发热的同时,能提供比单纯均匀抽帧更平滑连贯的播放体验。

帧保留模式详解

系统提供以下三种帧保留模式,供开发者按需切换。

模式 实现原理 使用场景
感知自适应(ADAPTIVE) 系统依据应用传入的当前倍速,动态分析视频运动特征,优先剔除视觉感知权重较低的非关键帧。 推荐使用本模式。主要用于高倍速播放场景,提供比无内容差别均匀抽帧更符合人眼视觉连贯性的平滑体验。
全量直通(FULL) 对所有输入帧进行解码输出,不进行丢帧处理。 适用于非倍速或慢速播放场景。
平滑定比(UNIFORM) 系统按开发者指定的固定比例均匀地进行抽帧。 适用于特殊的降载与提速场景,如高温场景下的降载降温,以及编辑预览场景下的拖拽流畅性提升。

参数说明

本能力需主动下发配置才可以生效。通过在OH_AVFormat中配置以下键值对来精确控制行为。

  1. OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_MODE(模式配置)

  2. OH_MD_KEY_VIDEO_DECODER_SPEED(解码倍速)

    • 类型:double
    • 取值范围:严格大于0.0。
    • 描述:配置或切换到感知自适应模式时,建议同时显式配置当前播放倍速,以获得最佳的算法准确性;倍速变化时建议同步更新。初始化为全量直通模式时无需配置。
  3. OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_RATIO(保留比例)

    • 类型:double
    • 取值范围:[0.01, 1.0](例如0.5表示保留50%的解码帧)。
    • 描述:仅在平滑定比模式下生效。当配置越界或异常时,系统默认以30fps为目标帧率进行兜底。

约束与限制

倍速播放场景开发实践

对于常规视频播放业务,建议采用初始化阶段配置与动态切换结合的策略。

[h2]初始化阶段配置

以下示例以正常倍速起播,配置全量直通模式。SetOptionalFormatFeatures在完成同步模式配置后,当sampleInfo.codec.isSmartFluencySupported为true时调用ConfigureSmartFluency(format)并检查返回值。随后由VideoDecoder::Configure调用OH_VideoDecoder_Configure()完成配置。该辅助函数仅设置本能力的参数,不负责创建或销毁OH_AVFormat。

如果业务直接以高倍速起播,也可在初始化阶段配置感知自适应模式,建议同时显式设置OH_MD_KEY_VIDEO_DECODER_SPEED为实际起播倍速。

bool ConfigureSmartFluency(OH_AVFormat *format)
{
    bool ret = OH_AVFormat_SetIntValue(format, OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_MODE,
        OH_FRAME_RETENTION_MODE_FULL);
    CHECK_AND_RETURN_RET_LOG(ret, false, "Set smart fluency initial mode failed");
    return true;
}

[h2]运行态按需切换

系统支持在运行态下动态切换帧保留模式。开发者可通过调用OH_VideoDecoder_SetParameter()实时下发配置,参数的生效时机与该接口的标准行为一致。

int32_t VideoDecoder::OnUserSpeedChanged(double targetSpeed)
{
    OH_AVFormat *param = OH_AVFormat_Create();
    CHECK_AND_RETURN_RET_LOG(param != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");

    // 引入epsilon处理double类型的精度比较。
    const double EPSILON = 1e-6;

    const bool enableAdaptive = targetSpeed > 1.0 + EPSILON;
    if (enableAdaptive) {
        // 场景:高倍速播放(如1.5x,2.0x,3.0x等)。
        // 策略:使能感知自适应模式。
        OH_AVFormat_SetIntValue(param, OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_MODE,
                                OH_FRAME_RETENTION_MODE_ADAPTIVE);
        OH_AVFormat_SetDoubleValue(param, OH_MD_KEY_VIDEO_DECODER_SPEED, targetSpeed);
    } else {
        // 场景:正常播放(1.0x)或慢速播放(<1.0x)。
        // 策略:切换到全量直通模式,保障帧帧送显。
        OH_AVFormat_SetIntValue(param, OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_MODE,
                                OH_FRAME_RETENTION_MODE_FULL);
    }

    // 实时下发参数,动态调整系统帧保留策略。
    int32_t ret = OH_VideoDecoder_SetParameter(decoder_, param);
    OH_AVFormat_Destroy(param);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
                             "SetParameter failed, ret: %{public}d", ret);
    if (enableAdaptive) {
        AVCODEC_SAMPLE_LOGI("Smart fluency mode changed to ADAPTIVE, speed: %{public}.2f", targetSpeed);
    } else {
        AVCODEC_SAMPLE_LOGI("Smart fluency mode changed to FULL");
    }
    return AVCODEC_SAMPLE_ERR_OK;
}

其他有益场景开发实践

除了在倍速播放场景下推荐使用本能力外,以下场景也可通过使用本能力获得性能和体验收益。

示例(以应对温控告警为例):

int32_t VideoDecoder::OnThermalWarningReceived(double ratio)
{
    OH_AVFormat *param = OH_AVFormat_Create();
    CHECK_AND_RETURN_RET_LOG(param != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "AVFormat create failed");

    // 采用UNIFORM平滑定比模式。
    OH_AVFormat_SetIntValue(param, OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_MODE,
                            OH_FRAME_RETENTION_MODE_UNIFORM);

    // 设定保留比例(如0.3表示仅保留30%的解码帧输出)。
    OH_AVFormat_SetDoubleValue(param, OH_MD_KEY_VIDEO_DECODER_FRAME_RETENTION_RATIO, ratio);

    // 实时下发生效,系统将执行均匀的抽帧剔除,降低整机负载。
    int32_t ret = OH_VideoDecoder_SetParameter(decoder_, param);
    OH_AVFormat_Destroy(param);
    CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR,
                             "SetParameter failed, ret: %{public}d", ret);
    return AVCODEC_SAMPLE_ERR_OK;
}