【鸿蒙南向开发】OpenHarmony实战之视频编解码HDI的使用

简介

Codec HDI 提供了基于OpenMax(简称OMX)的一整套编解码接口,程序通过简单的几步,即可实现基于OMX的硬件编解码。本文主要介绍基于Codec HDI 开发的编解码功能,包括初始化,Buffer流转以及释放等。

CODEC HDI框架介绍

image.png

Codec HDI Interface (简称HDI)提供基于OpenMax 的标准接口,Media Service 调用这套接口实现硬件编解码能力。HDI 另外提供了实现Callback 机制的接口,Media Service 可以通过HDI 接口创建Callback 信息接收服务端(Codec HDI Callback Remote Service),并且通过SetCallback 方法将对应的客户端代理(Codec HDI Callback Client Proxy)传给OpenMax 实现层,OpenMax 在数据Buffer 处理过程中会通过此代理调用回调方法,告知Media Service 进行对应的数据处理。

目录

./drivers/peripheral/codec
|-- hal									#HDI框架代码目录
|   |-- include							
|   |-- src
|-- hdi_service						    #原HDI框架代码目录
|   |-- codec_proxy
|   |-- codec_service_stub
|   |-- codec_test
|-- interfaces							#codec接口头文件
|   |-- include
|-- test								#unittest 和Demo目录

Codec HDI编解码实例

组件状态流转

image.png

1.通过调用CreateComponent函数,可以打开组件,并让组件进入OMX_StateLoaded 或OMX_StateWaitForResources 状态;
2.通过调用DestoryComponent函数,可以销毁处于OMX_StateLoaded状态的组件实例;
3.其它的状态变化,可以通过SendCommand(OMX_CommandStateSet, <OMX_STATETYPE>)使组件进入相应的状态。

状态

描述

OMX_StateInvalid

组件已损坏或者发生一个不能恢复的错误

OMX_StateLoaded

组件已经加载,但是资源未申请

OMX_StateIdle

组件已经申请到所有资源,但不会轮转任何buffer

OMX_StateExecuting

组件正在处理有效的数据

OMX_StatePause

组件暂停处理数据,可以通过设置组件状态唤醒重新处理数据

OMX_StateWaitForResources

组件正在等待所需要的

编解码流程简介

image.png

主要包含以下几步:

  1. 接口及回调初始化
  2. 组件初始化
  3. 设置编解码参数
  4. 申请输入输出Buffer
  5. 编解码
  6. 组件回调处理
  7. 组件释放

codec HDI编解码主要流程如上图显示,下面我们以解码流程来讲解。

接口及回调初始化

本步骤主要初始化了使用HDI接口必须使用的结构及初始化对应的回调函数。

//初始化HDI ComponentManager实例,用于打开OMX组件
omxMgr_ = GetCodecComponentManager();

//初始化回调
callback_ = CodecCallbackTypeStubGetInstance();
if (!omxMgr_ || !callback_) {
    FUNC_EXIT_ERR();
    return false;
}
//设置回调函数指针
callback_->EventHandler    = &OMXCore::OnEvent;
callback_->EmptyBufferDone = &OMXCore::OnEmptyBufferDone;
callback_->FillBufferDone  = &OMXCore::OnFillBufferDone;

组件初始化

组件初始化包含打开对应的编解码组件并获取组件的版本,后续会使用到该版本参数。

//新建组件实例,组件实例为 client_ 后续接口中需要使用 client_
auto err = omxMgr_->CreateComponent(&client_, "OMX.rk.video_decoder.avc", 0, 0, callback_);
if (err != HDF_SUCCESS) {
    HDF_LOGE("failed to CreateComponent");
    FUNC_EXIT_ERR();
    return false;
}
//获取组件版本号
char                  name[MAX_LEN] = {0};
union OMX_VERSIONTYPE omxVer;
union OMX_VERSIONTYPE omxVerspec;
uint8_t               uuid[MAX_LEN] = {0};
uint32_t              uuidLen   = MAX_LEN; // MAX_LEN = 128
err = client_->GetComponentVersion(client_, name, &omxVer, &omxVerspec, uuid, uuidLen);
if (err != HDF_SUCCESS) {
    HDF_LOGE("failed to CreateComponent");
    FUNC_EXIT_ERR();
    return false;
}

设置编解码参数

设置参数时会使用上一步获取到的版本信息,注意填写。

1.设置输入的宽和高

OMX_PARAM_PORTDEFINITIONTYPE param;
InitParam(param);
param.nPortIndex = (uint32_t)PortIndex::kPortIndexInput;
auto err         = client_
<think> 嗯,用户正在询问鸿蒙南向开发中实现烟雾报警的具体方法和技术细节。这个需求很明确,涉及硬件驱动开发、传感器数据采集和鸿蒙系统特性应用等专业领域。 用户可能是个物联网开发工程师,正在尝试将传统烟雾报警器接入鸿蒙生态。从提问方式看,ta应该具备基础开发经验,但可能刚接触OpenHarmony南向开发。深层需求可能是想了解完整的实现链路,而不仅仅是碎片化信息。 需要重点覆盖几个技术层面:首先是硬件选型,MQ系列传感器在鸿蒙生态的兼容性很关键;其次是驱动框架,HDF的标准化开发流程必须详细说明;最后是数据上报机制,用户肯定关心如何让传感器数据被上层应用识别。 注意到用户上次询问过"南向开发"这个关键词,说明ta对鸿蒙分层架构已有概念。这次可以更深入讨论驱动开发细节,比如HDF的轮询模式配置——很多开发者会卡在传感器数据采集频率的设置上。 代码示例需要精简但完整,重点展示HCS配置和轮询线程的实现。特别要强调vap_value的换算逻辑,这是烟雾报警特有的浓度转换公式。安全阈值设置部分也很实用,不同场所的报警阈值差异很大。 最后补充的注意事项其实比技术更重要。比如MQ-2传感器的预热特性,实际开发中容易忽略这点导致误报。还有中断模式与轮询模式的适用场景,这是涉及设备功耗的关键设计选择。 相关问题的延伸设计要有层次:从基础(传感器原理)到进阶(低功耗优化),最后到系统级(联动消防系统)。用户如果问出第三个问题,说明ta正在设计完整的智能消防方案,而不仅是单个设备开发。 </think> 在鸿蒙OpenHarmony南向开发中实现烟雾报警功能,需结合传感器驱动开发、数据采集和系统服务框架。以下是完整实现方案: --- ### **一、技术实现流程** 1. **硬件选型** - 烟雾传感器:MQ-2/MQ-5系列(模拟电压输出) - 主控芯片:Hi3861/Hi3516(兼容鸿蒙轻量系统) - 通信接口:ADC采集 + I²C/GPIO控制 2. **驱动层开发** ```c // drivers/peripheral/sensor/hal_smoke_detector.c #include "hdf_sensor.h" static int32_t ReadSmokeData(struct SensorBusCfg *busCfg, uint32_t *vapValue) { int32_t ret; uint32_t adcValue; ret = AdcRead(busCfg->adcChan, &adcValue); // ADC采集原始值 *vapValue = (adcValue * 5000) / 4096; // 换算为ppm(假设12位ADC) return ret; } struct SmokeDetectorOps g_smokeOps = { .GetSmokeData = ReadSmokeData }; int32_t HdfSmokeDriverInit(struct HdfDeviceObject *device) { HDF_LOGI("Smoke detector driver init"); return SensorRegisterChipOps(&g_smokeOps); // 注册传感器操作集 } ``` 3. **HCS配置(硬件抽象层)** ```hcs // vendor/hisilicon/hispark_taurus/sensor_config.hcs smoke_sensor_config { sensorName = "smoke_detector"; busType = 1; // 1表示ADC总线 adcChan = 3; // 使用ADC通道3 gpioIntNum = 12; // 中断GPIO引脚 pollingInterval = 200; // 200ms采样间隔 } ``` 4. **服务层告警逻辑** ```cpp // foundation/sensors/smoke_service.cpp void SmokeAlarmTask::Run() { while (true) { uint32_t smokePpm; GetSmokeData(&smokePpm); // 从驱动层读取数据 if (smokePpm > THRESHOLD_DANGER) { // 阈值设定(如1000ppm) TriggerAlarm(); // 触发本地蜂鸣器 ReportToSystem(SMOKE_EMERGENCY_EVENT); // 上报系统事件 } usleep(200000); // 200ms间隔 } } ``` --- ### **二、关键开发技术** 1. **鸿蒙传感器框架** - 使用`HDF`(Hardware Driver Foundation)统一驱动模型 - 注册传感器到`SensorService`:`SensorRegister(SENSOR_TYPE_SMOKE, &g_smokeDetector)` 2. **数据上报机制** ```cpp // 通过HDI接口上报事件 int32_t ReportToSystem(int eventId) { struct SensorEvent event; event.sensorTypeId = SENSOR_TYPE_SMOKE; event.data[0] = smokePpm; OHOS::HDI::Sensor::V1_0::ISensorInterface::Get()->PublishEvent(event); } ``` 3. **低功耗优化** - **中断模式**:配置GPIO中断唤醒系统(替代轮询) - **动态采样**:根据浓度自适应调整采集频率 ```c if (smokePpm < THRESHOLD_SAFE) { SetPollingInterval(1000); // 安全时降低至1s/次 } ``` --- ### **三、开发验证与调试** 1. **DevEco Device Tool调试** - 使用`hilog`查看实时数据: `hilog -D 0xD001D00 "Smoke ppm: %{public}d" smokePpm` 2. **模拟器测试** ```bash # 在qemu模拟器中注入测试事件 hdc shell inject_sensor -t smoke -a 1500 # 模拟浓度超标 ``` --- ### **四、注意事项** 1. **传感器校准** $$ V_{actual} = V_{read} \times \frac{R_{L}}{(R_{L} + R_{s})} \times V_{cc} $$ 其中 $R_s$ 为传感器电阻,需通过标准气体校准 2. **安全认证** - 需通过消防认证(如GB 20517) - 电磁兼容性测试(EMC) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值