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 中添加动态库链接:- target_link_libraries(sample PUBLIC liblowpower_avsink.so libhilog_ndk.z.so)
- set(BASE_LIBRARY
- libnative_media_codecbase.so libnative_media_core.so libnative_media_vdec.so libnative_window.so
- libnative_media_venc.so libnative_media_acodec.so libnative_media_avdemuxer.so libnative_media_avsource.so
- libohaudio.so
- )
- target_link_libraries(sample PUBLIC ${BASE_LIBRARY})
复制代码
引入头文件:- #include "multimedia/player_framework/lowpower_audio_sink_base.h"
- #include "multimedia/player_framework/lowpower_audio_sink.h"
- #include "multimedia/player_framework/lowpower_video_sink.h"
- #include "multimedia/player_framework/lowpower_video_sink_base.h"
复制代码
同时需要在 TypeScript 端声明 NAPI 接口,如 playNative、stopNative、pauseNative、resumeNative 等。
### 2. 创建播放器组件
使用 OH_AVSource_CreateWithFD 创建解封装器,获取媒体轨道信息,然后根据 MIME 类型创建对应的 LPP 播放器:- source_ = OH_AVSource_CreateWithFD(info.inputFd, info.inputFileOffset, info.inputFileSize);
- demuxer_ = OH_AVDemuxer_CreateWithSource(source_);
- lppVideoStreamer_ = OH_LowPowerVideoSink_CreateByMime(codecMime.c_str());
- lppAudioStreamer_ = OH_LowPowerAudioSink_CreateByMime(codecMime.c_str());
复制代码
### 3. 注册回调函数
创建回调对象并注册数据请求、进度更新等监听:- lppAudioStreamerCallback_ = OH_LowPowerAudioSinkCallback_Create();
- OH_LowPowerAudioSinkCallback_SetDataNeededListener(lppAudioStreamerCallback_, LppCallback::OnDataNeeded, lppUserData);
- OH_LowPowerAudioSinkCallback_SetPositionUpdateListener(lppAudioStreamerCallback_, LppCallback::OnPositionUpdated, lppUserData);
- ret = OH_LowPowerAudioSink_RegisterCallback(lppAudioStreamer_, lppAudioStreamerCallback_);
复制代码
### 4. 初始化参数设置
构造 OH_AVFormat 并填入视频分辨率、帧率、像素格式、旋转角度等,然后配置到视频播放器:- OH_AVFormat* format = OH_AVFormat_Create();
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_WIDTH, sampleInfo.videoWidth);
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_HEIGHT, sampleInfo.videoHeight);
- OH_AVFormat_SetDoubleValue(format, OH_MD_KEY_FRAME_RATE, sampleInfo.frameRate);
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_PIXEL_FORMAT, sampleInfo.pixelFormat);
- OH_AVFormat_SetIntValue(format, OH_MD_KEY_ROTATION, sampleInfo.rotation);
- ret = OH_LowPowerVideoSink_Configure(lppVideoStreamer_, format);
- // 视频流需要挂载显示窗口:OH_LowPowerVideoSink_SetVideoSurface(lppVideoStreamer_, surfaceId);
复制代码
### 5. 预加载与状态流转
绑定音画同步后执行 Prepare,然后启动解码器和渲染器:- OH_LowPowerVideoSink_SetSyncAudioSink(lppVideoStreamer_, lppAudioStreamer_);
- OH_LowPowerVideoSink_Prepare(lppVideoStreamer_);
- OH_LowPowerVideoSink_StartDecoder(lppVideoStreamer_);
- OH_LowPowerVideoSink_StartRenderer(lppVideoStreamer_);
复制代码
### 6. 播放控制
支持暂停、恢复、停止、设置音量、播放速度、Seek 后 Flush 等:- OH_LowPowerVideoSink_Pause(lppVideoStreamer_);
- OH_LowPowerVideoSink_Resume(lppVideoStreamer_);
- OH_LowPowerVideoSink_Stop(lppVideoStreamer_);
- OH_LowPowerAudioSink_SetVolume(lppAudioStreamer_, 0.8f);
- OH_LowPowerVideoSink_SetPlaybackSpeed(lppVideoStreamer_, 1.5f);
- OH_LowPowerVideoSink_Flush(lppVideoStreamer_);
复制代码
### 7. 重置与销毁
切换源时调用 Reset 重置资源,彻底退出时调用 Destroy 释放:- OH_LowPowerVideoSink_Destroy(lppVideoStreamer_);
- 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 调用和资源管理,即可打造极致续航的多媒体体验。 |