查看: 135|回复: 1

HarmonyOS 6 LPP低功耗播放器实战:NDK接入原理与开发步骤

[复制链接]
发表于 3 小时前 | 显示全部楼层 |阅读模式
HarmonyOS 6 从 API version 20 开始引入了 Low Power Player(LPP)低功耗播放器,它通过硬件加速和智能资源调度,在不牺牲播放体验的前提下大幅降低功耗。本文基于实战体验,详细介绍如何在 NDK(C/C++)层使用 LPP 播放本地视频,涵盖原理、状态机流转、核心开发步骤及最佳实践。

## 一、LPP 低功耗播放的实现原理

LPP 的能效优势源于以下几项设计:

- **硬件加速解码核心**:强制调用 GPU 或媒体处理单元进行底层视频解码,高清/4K 视频流下相比纯软件解码可减少约 30%–50% 的功耗。
- **智能生命周期资源调度**:播放器暂停或停止时,底层解封装器、解码器资源自动深睡或释放;通过 _SetDataNeededListener 回调实现按需加载,避免无意义的内存占用。
- **事件驱动的无缝衔接**:通过 _SetInterruptListener 监听音频焦点抢占,通过 _SetDeviceChangeListener 处理设备切换,通过 _SetErrorListener 实现快速降级处理。
- **极简高效数据流转**:使用 OH_AVSamplesBuffer_AppendOneBuffer 实现零拷贝传输,利用 _SetTargetStartFrame 精准定位帧画面,减少 Seek 时冗余解码。
- **功耗自适应防御**:从 API 21 开始需先通过 _GetCapability 检测硬件是否支持 LPP,若不支持则回退到标准 AVCodec;应用退入后台时,依赖 Window Surface 或 XComponent 自动降频剔帧。

总结来说,LPP 的核心是“按需分配资源 + 硬件卸载计算”,通过有限状态机管理和系统事件驱动,最小化渲染模块活跃时长。

## 二、播放流程与状态机流转

LPP 播放生命周期包含五个阶段:Created → Initialized → Ready → Decoding → Rendering。

- **创建**:调用 _CreateByMime 创建解码器实例。
- **初始化/配置**:完成 Configure 后进入 Initialized 状态;Prepare 预加载资源后进入 Ready。
- **开始工作**:StartDecode 进入 Decoding,触发 RenderFirstFrame,再 StartRender 进入 Rendering。
- **控制逻辑**:Pause 进入 Paused(资源未释放),Resume 恢复 Rendering;Stop 进入 Stopped;流结束进入 Eos。
- **异常恢复**:出现错误时需 Reset 或直接 Destroy 释放资源。

注意:处于 Ready/Decoding/Rendering/Paused/Stopped 状态时播放引擎占用较多资源,暂停后应尽早 Reset 或 Destroy。

## 三、NDK 实战开发步骤

LPP 接入依赖 liblowpower_avsink.so 模块。

### 1. 前置声明与链接

在 CMake 中添加动态库链接:
  1. target_link_libraries(sample PUBLIC liblowpower_avsink.so libhilog_ndk.z.so)
  2. set(BASE_LIBRARY
  3.     libnative_media_codecbase.so libnative_media_core.so libnative_media_vdec.so libnative_window.so
  4.     libnative_media_venc.so libnative_media_acodec.so libnative_media_avdemuxer.so libnative_media_avsource.so
  5.     libohaudio.so
  6. )
  7. target_link_libraries(sample PUBLIC ${BASE_LIBRARY})
复制代码

引入头文件:
  1. #include "multimedia/player_framework/lowpower_audio_sink_base.h"
  2. #include "multimedia/player_framework/lowpower_audio_sink.h"
  3. #include "multimedia/player_framework/lowpower_video_sink.h"
  4. #include "multimedia/player_framework/lowpower_video_sink_base.h"
复制代码

同时需要在 TypeScript 端声明 NAPI 接口,如 playNative、stopNative、pauseNative、resumeNative 等。

### 2. 创建播放器组件

使用 OH_AVSource_CreateWithFD 创建解封装器,获取媒体轨道信息,然后根据 MIME 类型创建对应的 LPP 播放器:
  1. source_ = OH_AVSource_CreateWithFD(info.inputFd, info.inputFileOffset, info.inputFileSize);
  2. demuxer_ = OH_AVDemuxer_CreateWithSource(source_);
  3. lppVideoStreamer_ = OH_LowPowerVideoSink_CreateByMime(codecMime.c_str());
  4. lppAudioStreamer_ = OH_LowPowerAudioSink_CreateByMime(codecMime.c_str());
复制代码

### 3. 注册回调函数

创建回调对象并注册数据请求、进度更新等监听:
  1. lppAudioStreamerCallback_ = OH_LowPowerAudioSinkCallback_Create();
  2. OH_LowPowerAudioSinkCallback_SetDataNeededListener(lppAudioStreamerCallback_, LppCallback::OnDataNeeded, lppUserData);
  3. OH_LowPowerAudioSinkCallback_SetPositionUpdateListener(lppAudioStreamerCallback_, LppCallback::OnPositionUpdated, lppUserData);
  4. ret = OH_LowPowerAudioSink_RegisterCallback(lppAudioStreamer_, lppAudioStreamerCallback_);
复制代码

### 4. 初始化参数设置

构造 OH_AVFormat 并填入视频分辨率、帧率、像素格式、旋转角度等,然后配置到视频播放器:
  1. OH_AVFormat* format = OH_AVFormat_Create();
  2. OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
  3. OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
  4. OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
  5. OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat);
  6. OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.rotation);
  7. ret = OH_LowPowerVideoSink_Configure(lppVideoStreamer_, format);
  8. // 视频流需要挂载显示窗口:OH_LowPowerVideoSink_SetVideoSurface(lppVideoStreamer_, surfaceId);
复制代码

### 5. 预加载与状态流转

绑定音画同步后执行 Prepare,然后启动解码器和渲染器:
  1. OH_LowPowerVideoSink_SetSyncAudioSink(lppVideoStreamer_, lppAudioStreamer_);
  2. OH_LowPowerVideoSink_Prepare(lppVideoStreamer_);
  3. OH_LowPowerVideoSink_StartDecoder(lppVideoStreamer_);
  4. OH_LowPowerVideoSink_StartRenderer(lppVideoStreamer_);
复制代码

### 6. 播放控制

支持暂停、恢复、停止、设置音量、播放速度、Seek 后 Flush 等:
  1. OH_LowPowerVideoSink_Pause(lppVideoStreamer_);
  2. OH_LowPowerVideoSink_Resume(lppVideoStreamer_);
  3. OH_LowPowerVideoSink_Stop(lppVideoStreamer_);
  4. OH_LowPowerAudioSink_SetVolume(lppAudioStreamer_, 0.8f);
  5. OH_LowPowerVideoSink_SetPlaybackSpeed(lppVideoStreamer_, 1.5f);
  6. OH_LowPowerVideoSink_Flush(lppVideoStreamer_);
复制代码

### 7. 重置与销毁

切换源时调用 Reset 重置资源,彻底退出时调用 Destroy 释放:
  1. OH_LowPowerVideoSink_Destroy(lppVideoStreamer_);
  2. OH_LowPowerAudioSink_Destroy(lppAudioStreamer_);
复制代码

## 四、API 使用建议

- **硬件能力检测**:从 API 21 开始,先调用 OH_LowPowerAVSink_GetCapability 确认设备支持,否则回退到 AVCodec。
- **音频焦点**:通过 OH_LowPowerAudioSinkCallback_SetInterruptListener 监听打断事件并做出响应。
- **设备切换**:注册 OH_LowPowerAudioSinkCallback_SetDeviceChangeListener 处理蓝牙断开等场景。
- **错误兜底**:通过 SetErrorListener 监听异常并进行降级处理。
- **数据填充**:使用 OH_AVDemuxer_ReadSampleBuffer 读取轨道数据,OH_AVSamplesBuffer_AppendOneBuffer 封装后通过 _ReturnSamples 通知播放器消费。
- **资源释放**:所有 Create 创建的实例必须对应调用 Destroy 释放硬件资源。
- **其他回调**:还可注册 SetEosListener、SetRenderStartListener、SetStreamChangedListener、SetFirstFrameDecodedListener 等。

## 五、适用场景

- **长视频沉浸式播放**:电影、剧集等,利用硬件卸载大幅降低能耗。
- **长音频伴随式场景**:后台视频挂载或锁屏播放时保持音画同步且省电。
- **低功耗直播流监听**:长时间开启渲染管线的监控类应用,按需加载降低负载。
- **NDK 资产对接**:现有 C/C++ 引擎可直接集成 LPP 的 NDK API 实现高性能集成。

掌握 LPP 是进阶鸿蒙音视频开发的关键,通过合理的 API 调用和资源管理,即可打造极致续航的多媒体体验。
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层

Re: HarmonyOS 6 LPP低功耗播放器实战:NDK接入原理与开发步骤

感谢分享!很详细的实战教程,尤其是状态机流转和NDK接入步骤非常清晰。请教一下:在实际应用中,LPP对硬件的依赖程度高吗?如果设备不支持硬件加速,回退到标准AVCodec的降级逻辑有没有什么坑需要注意?另外,你提到的`_SetTargetStartFrame`配合零拷贝传输,在实现精准Seek时是不是能明显减少卡顿?期待更多实战数据对比。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-5 18:22 , Processed in 0.024736 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部