未验证 提交 30367824 编写于 作者: O openharmony_ci 提交者: Gitee

!19122 Codec指导文档整改

Merge pull request !19122 from 王勃懿/master
......@@ -54,33 +54,33 @@ Codec模块主要完成对视频数据的硬件编解码,将H264等裸流数
### 接口说明
- codec_component_manager.h
- icodec_component_manager.h
| 接口名称 | 功能描述 |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------|
| int32_t (*CreateComponent)(struct CodecComponentType **component, uint32_t *componentId, char *compName, int64_t appData, struct CodecCallbackType *callbacks) | 创建Codec组件实例 |
| int32_t (*DestroyComponent)(uint32_t componentId) | 销毁Codec组件实例 |
| int32_t CreateComponent(sptr<ICodecComponent>& component, uint32_t& componentId,<br />const std::string& compName, int64_t appData, const sptr<ICodecCallback>& callbacks) | 创建Codec组件实例 |
| int32_t DestoryComponent(uint32_t componentId) | 销毁Codec组件实例 |
- codec_component _if.h
- icodec_component.h
| 接口名称 | 功能描述 |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| int32_t (*SendCommand)(struct CodecComponentType *self, enum OMX_COMMANDTYPE cmd, uint32_t param, int8_t *cmdData, uint32_t cmdDataLen) | 发送命令给组件 |
| int32_t (*GetParameter)(struct CodecComponentType *self, uint32_t paramIndex, int8_t *paramStruct, uint32_t paramStructLen) | 获取组件参数设置 |
| int32_t (*SetParameter)(struct CodecComponentType *self, uint32_t index, int8_t *paramStruct, uint32_t paramStructLen) | 设置组件需要的参数 |
| int32_t (*GetState)(struct CodecComponentType *self, enum OMX_STATETYPE *state) | 获取组件的状态 |
| int32_t (*UseBuffer)(struct CodecComponentType *self, uint32_t portIndex, struct OmxCodecBuffer *buffer) | 指定组件端口的buffer |
| int32_t (*FreeBuffer)(struct CodecComponentType *self, uint32_t portIndex, const struct OmxCodecBuffer *buffer) | 释放buffer |
| int32_t (*EmptyThisBuffer)(struct CodecComponentType *self, const struct OmxCodecBuffer *buffer) | 编解码输入待处理buffer |
| int32_t (*FillThisBuffer)(struct CodecComponentType *self, const struct OmxCodecBuffer *buffer) | 编解码输出填充buffer |
- codec_callback_if.h
| ------------------------------------------------------------ | ---------------------- |
| int32_t SendCommand(CodecCommandType cmd, uint32_t param, const std::vector<int8_t>& cmdData) | 发送命令给组件 |
| int32_t GetParameter(uint32_t index, const std::vector<int8_t>& inParamStruct, std::vector<int8_t>& outParamStruct) | 获取组件参数设置 |
| int32_t SetParameter(uint32_t index, const std::vector<int8_t>& paramStruct) | 设置组件需要的参数 |
| int32_t GetState(CodecStateType& state) | 获取组件的状态 |
| int32_t UseBuffer(uint32_t portIndex, const OmxCodecBuffer& inBuffer, OmxCodecBuffer& outBuffer) | 指定组件端口的buffer |
| int32_t FreeBuffer(uint32_t portIndex, const OmxCodecBuffer& buffer) | 释放buffer |
| int32_t EmptyThisBuffer(const OmxCodecBuffer& buffer) | 编解码输入待处理buffer |
| int32_t FillThisBuffer(const OmxCodecBuffer& buffer) | 编解码输出填充buffer |
- icodec_callback.h
| 接口名称 | 功能描述 |
| ---------------------------------------------------------------------------------------------------------------- |----------------------------------- |
| int32_t (*EventHandler)(struct CodecCallbackType *self, enum OMX_EVENTTYPE event, struct EventInfo *info) | 事件上报 |
| int32_t (*EmptyBufferDone)(struct CodecCallbackType *self, int64_t appData, const struct OmxCodecBuffer *buffer) | 上报输入buffer编码或者解码处理完毕 |
| int32_t (*FillBufferDone)(struct CodecCallbackType *self, int64_t appData, const struct OmxCodecBuffer *buffer) | 上报输出buffer填充完毕 |
| ------------------------------------------------------------ | ---------------------------------- |
| int32_t EventHandler(CodecEventType event, const EventInfo& info) | 事件上报 |
| int32_t EmptyBufferDone(int64_t appData, const OmxCodecBuffer& buffer) | 上报输入buffer编码或者解码处理完毕 |
| int32_t FillBufferDone(int64_t appData, const OmxCodecBuffer& buffer) | 上报输出buffer填充完毕 |
更多接口请参考[Codec驱动仓](https://gitee.com/openharmony/drivers_peripheral/tree/master/codec)
......@@ -88,63 +88,63 @@ Codec模块主要完成对视频数据的硬件编解码,将H264等裸流数
Codec HDI驱动的开发过程主要包含以下步骤:
#### Driver的注册及初始化
定义Codec HDI的HdfDriverEntry结构体,该结构体中定义了Driver初始化的方法,填充g_codecComponentDriverEntry结构体,实现Bind、Init、Release函数指针。
定义Codec HDI的HdfDriverEntry结构体,该结构体中定义了Driver初始化的方法,填充g_codeccomponentmanagerDriverEntry结构体,实现Bind、Init、Release函数指针。
```c
struct HdfDriverEntry g_codecComponentDriverEntry = {
static struct HdfDriverEntry g_codeccomponentmanagerDriverEntry = {
.moduleVersion = 1,
.moduleName = "codec_hdi_omx_server",
.Bind = HdfCodecComponentTypeDriverBind,
.Init = HdfCodecComponentTypeDriverInit,
.Release = HdfCodecComponentTypeDriverRelease,
};
HDF_INIT(g_codecComponentDriverEntry); // 将Codec HDI的HdfDriverEntry结构体注册到HDF上
.moduleName = "codec_component_manager_service",
.Bind = HdfCodecComponentManagerDriverBind,
.Init = HdfCodecComponentManagerDriverInit,
.Release = HdfCodecComponentManagerDriverRelease,
}; // 将Codec HDI的HdfDriverEntry结构体注册到HDF上
```
- HdfCodecComponentTypeDriverBind:将HDF中device绑定到CodecComponentTypeHost,将codec service注册到HDF框架。
- HdfCodecComponentManagerDriverBind:将HDF中device绑定到HdfCodecComponentManagerHost,将codec service注册到HDF框架。
```c
int32_t HdfCodecComponentTypeDriverBind(struct HdfDeviceObject *deviceObject)
static int HdfCodecComponentManagerDriverBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HdfCodecComponentTypeDriverBind enter.");
struct HdfCodecComponentTypeHost *omxcomponenttypeHost =
(struct HdfCodecComponentTypeHost *)OsalMemAlloc(sizeof(struct HdfCodecComponentTypeHost));
if (omxcomponenttypeHost == NULL) {
HDF_LOGE("HdfCodecComponentTypeDriverBind OsalMemAlloc HdfCodecComponentTypeHost failed!");
CODEC_LOGI("HdfCodecComponentManagerDriverBind enter");
auto *hdfCodecComponentManagerHost = new (std::nothrow) HdfCodecComponentManagerHost;
if (hdfCodecComponentManagerHost == nullptr) {
CODEC_LOGE("failed to create create HdfCodecComponentManagerHost object");
return HDF_FAILURE;
}
int ret = HdfDeviceObjectSetInterfaceDesc(deviceObject, COMPONENT_MANAGER_SERVICE_DESC);
if (ret != HDF_SUCCESS) {
HDF_LOGE("Failed to set interface desc");
return ret;
hdfCodecComponentManagerHost->ioService.Dispatch = CodecComponentManagerDriverDispatch;
hdfCodecComponentManagerHost->ioService.Open = NULL;
hdfCodecComponentManagerHost->ioService.Release = NULL;
auto serviceImpl = ICodecComponentManager::Get(true);
if (serviceImpl == nullptr) {
CODEC_LOGE("failed to get of implement service");
delete hdfCodecComponentManagerHost;
return HDF_FAILURE;
}
omxcomponenttypeHost->ioservice.Dispatch = CodecComponentTypeDriverDispatch;
omxcomponenttypeHost->ioservice.Open = NULL;
omxcomponenttypeHost->ioservice.Release = NULL;
omxcomponenttypeHost->service = CodecComponentManagerSerivceGet();
if (omxcomponenttypeHost->service == NULL) {
OsalMemFree(omxcomponenttypeHost);
hdfCodecComponentManagerHost->stub =
OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, ICodecComponentManager::GetDescriptor());
if (hdfCodecComponentManagerHost->stub == nullptr) {
CODEC_LOGE("failed to get stub object");
delete hdfCodecComponentManagerHost;
return HDF_FAILURE;
}
deviceObject->service = &omxcomponenttypeHost->ioservice;
deviceObject->service = &hdfCodecComponentManagerHost->ioService;
return HDF_SUCCESS;
}
```
- HdfCodecComponentTypeDriverInit:加载HCS(HDF Configuration Source)中的属性配置。
- HdfCodecComponentManagerDriverInit:加载HCS(HDF Configuration Source)中的属性配置。
```c
int32_t HdfCodecComponentTypeDriverInit(struct HdfDeviceObject *deviceObject)
static int HdfCodecComponentManagerDriverInit(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HdfCodecComponentTypeDriverInit enter.");
if (deviceObject == NULL) {
return HDF_FAILURE;
}
InitDataNode(deviceObject->property);
if (LoadCapabilityData() != HDF_SUCCESS) {
ClearCapabilityData();
CODEC_LOGI("HdfCodecComponentManagerDriverInit enter");
if (DevHostRegisterDumpHost(CodecDfxService::DevCodecHostDump) != HDF_SUCCESS) {
CODEC_LOGE("DevHostRegisterDumpHost error!");
}
return HDF_SUCCESS;
}
......@@ -153,14 +153,17 @@ HDF_INIT(g_codecComponentDriverEntry); // 将Codec HDI的HdfDriverEntry结构体
- HdfCodecComponentTypeDriverRelease:释放驱动实例。
```c
void HdfCodecComponentTypeDriverRelease(struct HdfDeviceObject *deviceObject)
static void HdfCodecComponentManagerDriverRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HdfCodecComponentTypeDriverRelease enter.");
struct HdfCodecComponentTypeHost *omxcomponenttypeHost =
CONTAINER_OF(deviceObject->service, struct HdfCodecComponentTypeHost, ioservice);
OmxComponentManagerSeriveRelease(omxcomponenttypeHost->service);
OsalMemFree(omxcomponenttypeHost);
ClearCapabilityData();
CODEC_LOGI("HdfCodecComponentManagerDriverRelease enter");
if (deviceObject->service == nullptr) {
CODEC_LOGE("HdfCodecComponentManagerDriverRelease not initted");
return;
}
auto *hdfCodecComponentManagerHost =
CONTAINER_OF(deviceObject->service, struct HdfCodecComponentManagerHost, ioService);
delete hdfCodecComponentManagerHost;
}
```
......@@ -177,19 +180,19 @@ vendor/hihope/rk3568/hdf_config/uhdf/
1. device相关配置
在device_info.hcs的codec_host中增加codec_omx_service配置,具体配置如下:
在device_info.hcs的codec_host中增加codec_component_manager_service配置,具体配置如下:
```c
codec :: host {
hostName = "codec_host";
priority = 50;
gid = ["codec_host", "uhdf_driver", "vendor_mpp_driver"];
codec_omx_device :: device {
codec_omx_idl_device :: device {
device0 :: deviceNode {
policy = 2; // 自动加载,非延迟加载
priority = 100; // 优先级
moduleName = "libcodec_hdi_omx_server.z.so"; // 驱动的动态库
serviceName = "codec_hdi_omx_service"; // 配置驱动的服务名
deviceMatchAttr = "codec_component_capabilities"; // 属性配置
moduleName = "libcodec_driver.z.so"; // 驱动的动态库
serviceName = "codec_component_manager_service"; // 配置驱动的服务名
deviceMatchAttr = "media_codec_capabilities"; // 属性配置
}
}
}
......@@ -197,7 +200,7 @@ vendor/hihope/rk3568/hdf_config/uhdf/
2. 支持的组件相关配置
在media_codec\codec_component_capabilities.hcs中增加组件配置,具体配置如下:
在media_codec\media_codec_capabilities.hcs中增加组件配置,具体配置如下:
```c
/* node name explanation -- HDF_video_hw_enc_avc_rk:
**
......@@ -228,7 +231,7 @@ vendor/hihope/rk3568/hdf_config/uhdf/
maxBlocksPerSecond = 0xFFFFFFFF;
blockSizeWidth = 0xFFFFFFFF;
blockSizeHeight = 0xFFFFFFFF;
supportPixelFmts = [28, 24, 30, 22, 7, 3, 14, 13, 20, 26, 27, 12]; // 支持的颜色列表,Display支持的颜色列表
supportPixelFmts = [28, 24, 20, 12]; // 支持的颜色列表,Display支持的颜色列表
measuredFrameRate = [320, 240, 165, 165, 720, 480, 149, 149, 1280, 720, 73, 73, 1920, 1080, 18, 18];
bitRateMode = [1, 2]; // 比特率模式,BitRateMode
minFrameRate = 0; // 帧率配置
......@@ -247,34 +250,29 @@ vendor/hihope/rk3568/hdf_config/uhdf/
1. 初始化,包括接口实例、回调的初始化和对应的组件的初始化;
2. 设置编解码参数和配置信息,如视频宽、高和码率等;
3. 输入输出Buffer申请;
4. 编解码Buffer流转,使组件进入OMX_Executing状态,并处理相应的回调;
4. 编解码Buffer流转,使组件进入CODEC_STATE_EXECUTING状态,并处理相应的回调;
5. 接口去初始化,销毁buffer,关闭组件并释放所有的接口对象;
#### 初始化
初始化过程包括接口的初始化,回调的初始化以及组件的创建。
```cpp
// 初始化Codec HDI ComponentManager实例
omxMgr_ = GetCodecComponentManager();
omxMgr_ = ICodecComponentManager::Get(false);
if ((omxMgr_ == nullptr)) {
HDF_LOGE("%{public}s omxMgr_ is null", __func__);
return false;
}
// 初始化回调
callback_ = CodecCallbackTypeStubGetInstance();
if (!omxMgr_ || !callback_) {
FUNC_EXIT_ERR();
callback_ = new CodecHdiCallback(shared_from_this());
if ((callback_ == nullptr)) {
HDF_LOGE("%{public}s callback_ is null", __func__);
return false;
}
// 设置回调函数指针
callback_->EventHandler = &OMXCore::OnEvent;
callback_->EmptyBufferDone = &OMXCore::OnEmptyBufferDone;
callback_->FillBufferDone = &OMXCore::OnFillBufferDone;
// 新建组件实例
uint32_t err = HDF_SUCCESS;
if (codec == codecMime::AVC) {
err = omxMgr_->CreateComponent(&client_, &componentId_, const_cast<char *>(DECODER_AVC), (int64_t)this,
callback_);
} else {
err = omxMgr_->CreateComponent(&client_, &componentId_, const_cast<char *>(DECODER_HEVC), (int64_t)this,
callback_);
err = omxMgr_->CreateComponent(client_, componentId_, compName, reinterpret_cast<int64_t>(this), callback_);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed to CreateComponent", __func__);
return false;
}
```
......@@ -283,64 +281,79 @@ Codec HDI编解码参数配置,包括输入输出数据的宽和高,输入
```cpp
// 设置输入端口图片的宽高
OMX_PARAM_PORTDEFINITIONTYPE param;
InitParam(param);
param.nPortIndex = (uint32_t)PortIndex::PORT_INDEX_INPUT;
auto err = client_->GetParameter(client_, OMX_IndexParamPortDefinition, (int8_t *)&param, sizeof(param));
if (util_->InitParam(param) != HDF_SUCCESS) {
return HDF_FAILURE;
}
param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_INPUT);
std::vector<int8_t> inVec, outVec;
util_->ObjectToVector(param, inVec);
auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
return false;
return err;
}
util_->VectorToObject(outVec, param);
HDF_LOGI("PortIndex::PORT_INDEX_INPUT: eCompressionFormat = %{public}d, eColorFormat = %{public}d ",
param.format.video.eCompressionFormat, param.format.video.eColorFormat);
param.format.video.nFrameWidth = width_;
param.format.video.nFrameHeight = height_;
param.format.video.nStride = width_;
param.format.video.nSliceHeight = height_;
err = client_->SetParameter(client_, OMX_IndexParamPortDefinition, (int8_t *)&param, sizeof(param));
util_->setParmValue(param, width_, height_, stride_);
util_->ObjectToVector(param, inVec);
err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT, index is OMX_IndexParamPortDefinition", __func__);
return false;
return err;
}
// 输出宽、高和格式设置
InitParam(param);
param.nPortIndex = (uint32_t)PortIndex::PORT_INDEX_OUTPUT;
err = client_->GetParameter(client_, OMX_IndexParamPortDefinition, (int8_t *)&param, sizeof(param));
if (util_->InitParam(param) != HDF_SUCCESS) {
return HDF_FAILURE;
}
param.nPortIndex = static_cast<uint32_t>(PortIndex::PORT_INDEX_OUTPUT);
util_->ObjectToVector(param, inVec);
err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition", __func__);
return false;
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
__func__);
return err;
}
util_->VectorToObject(outVec, param);
HDF_LOGI("PortIndex::PORT_INDEX_OUTPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
param.format.video.eCompressionFormat, param.format.video.eColorFormat);
param.format.video.nFrameWidth = width_;
param.format.video.nFrameHeight = height_;
param.format.video.nStride = width_;
param.format.video.nSliceHeight = height_;
util_->setParmValue(param, width_, height_, stride_);
param.format.video.eColorFormat = AV_COLOR_FORMAT; // 输出数据格式设置为YUV420SP
err = client_->SetParameter(client_, OMX_IndexParamPortDefinition, (int8_t *)&param, sizeof(param));
err = client_->SetParameter(OMX_IndexParamPortDefinition, inVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_OUTPUT, index is OMX_IndexParamPortDefinition",
__func__);
return false;
return err;
}
// 设置输入数据为H264/H265格式数据
OMX_VIDEO_PARAM_PORTFORMATTYPE param;
InitParam(param);
if (util_->InitParam(param) != HDF_SUCCESS) {
return false;
}
param.nPortIndex = (uint32_t)PortIndex::PORT_INDEX_INPUT;
auto err = client_->GetParameter(client_, OMX_IndexParamVideoPortFormat, (int8_t *)&param, sizeof(param));
std::vector<int8_t> inVec, outVec;
util_->ObjectToVector(param, inVec);
auto err = client_->GetParameter(OMX_IndexParamVideoPortFormat, inVec, outVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__);
return false;
}
util_->VectorToObject(outVec, param);
HDF_LOGI("set Format PortIndex::PORT_INDEX_INPUT eCompressionFormat = %{public}d, eColorFormat=%{public}d",
param.eCompressionFormat, param.eColorFormat);
param.xFramerate = FRAME; // 30帧
param.xFramerate = FRAME // 30帧
if (codecMime_ == codecMime::AVC) {
param.eCompressionFormat = OMX_VIDEO_CodingAVC; // H264
} else {
param.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)CODEC_OMX_VIDEO_CodingHEVC; // H265
}
err = client_->SetParameter(client_, OMX_IndexParamVideoPortFormat, (int8_t *)&param, sizeof(param));
util_->ObjectToVector(param, inVec);
err = client_->SetParameter(OMX_IndexParamVideoPortFormat, inVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed with PortIndex::PORT_INDEX_INPUT", __func__);
return false;
......@@ -352,90 +365,97 @@ if (err != HDF_SUCCESS) {
1. 用户通过UseBuffer申请输入输出Buffer,并保存bufferId,后续buffer轮转可以直接通过bufferId来操作。
2. 用户需要判断对应的端口是否是使能状态,如果不是,需要先将对应的端口设置为使能状态。
3. 用户通过SendCommand将组件的状态为修改为OMX_StateIdle,需要等待其结果通知。
3. 用户通过SendCommand将组件的状态为修改为CODEC_STATE_IDLE,需要等待其结果通知。
```cpp
// 输入端口buffer申请
auto ret = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
if (!ret) {
auto err = UseBufferOnPort(PortIndex::PORT_INDEX_INPUT);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_INPUT error", __func__);
return false;
}
// 输出端口buffer申请
ret = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
if (!ret) {
err = UseBufferOnPort(PortIndex::PORT_INDEX_OUTPUT);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s UseBufferOnPort PortIndex::PORT_INDEX_OUTPUT error", __func__);
return false;
}
// 发送命令使组件进入OMX_StateIdle状态
auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0);
std::vector<int8_t> cmdData;
auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, cmdData);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__);
HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
return false;
}
HDF_LOGI("Wait for OMX_StateIdle status");
this->WaitForStatusChanged();
```
UseBufferOnPort实现如下:
```cpp
bool CodecHdiDecode::UseBufferOnPort(enum PortIndex portIndex)
int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex)
{
HDF_LOGI("%{public}s enter, portIndex = %{public}d", __func__, portIndex);
int bufferSize = 0;
int bufferCount = 0;
bool bPortEnable = false;
bool PortEnable = false;
// 获取端口buffer参数
OMX_PARAM_PORTDEFINITIONTYPE param;
InitParam(param);
param.nPortIndex = (OMX_U32)portIndex;
auto err = client_->GetParameter(client_, OMX_IndexParamPortDefinition, (int8_t *)&param, sizeof(param));
if (util_->InitParam(param) != HDF_SUCCESS) {
return HDF_FAILURE;
}
param.nPortIndex = static_cast<OMX_U32>(portIndex);
std::vector<int8_t> inVec, outVec;
util_->ObjectToVector(param, inVec);
auto err = client_->GetParameter(OMX_IndexParamPortDefinition, inVec, outVec);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed to GetParameter with OMX_IndexParamPortDefinition : portIndex[%{public}d]",
__func__, portIndex);
return false;
return err;
}
util_->VectorToObject(outVec, param);
bufferSize = param.nBufferSize;
bufferCount = param.nBufferCountActual;
bPortEnable = param.bEnabled;
portEnable = param.bEnabled;
HDF_LOGI("buffer index [%{public}d], buffer size [%{public}d], "
"buffer count [%{public}d], portEnable[%{public}d], err [%{public}d]",
portIndex, bufferSize, bufferCount, bPortEnable, err);
{
OMX_PARAM_BUFFERSUPPLIERTYPE param;
InitParam(param);
param.nPortIndex = (uint32_t)portIndex;
auto err = client_->GetParameter(client_, OMX_IndexParamCompBufferSupplier, (int8_t *)&param, sizeof(param));
HDF_LOGI("param.eBufferSupplier[%{public}d] isSupply [%{public}d], err [%{public}d]", param.eBufferSupplier,
this->isSupply_, err);
}
"buffer count [%{public}d], portEnable[%{public}d], ret [%{public}d]",
portIndex, bufferSize, bufferCount, portEnable, err);
// 设置端口buffer
UseBufferOnPort(portIndex, bufferCount, bufferSize);
if (useBufferHandle_ && portIndex == PortIndex::PORT_INDEX_OUTPUT) {
err = UseBufferHandle(bufferCount, bufferSize);
} else {
err = UseBufferOnPort(portIndex, bufferCount, bufferSize);
}
// 检查端口是否可用状态
if (!bPortEnable) {
auto err = client_->SendCommand(client_, OMX_CommandPortEnable, (uint32_t)portIndex, NULL, 0);
if (!portEnable) {
err = client_->SendCommand(CODEC_COMMAND_PORT_ENABLE, static_cast<uint32_t>(portIndex), {});
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s SendCommand OMX_CommandPortEnable::PortIndex::PORT_INDEX_INPUT error", __func__);
return false;
return err;
}
}
return true;
return HDF_SUCCESS;
}
bool CodecHdiDecode::UseBufferOnPort(enum PortIndex portIndex, int bufferCount, int bufferSize)
int32_t CodecHdiDecode::UseBufferOnPort(PortIndex portIndex, int bufferCount, int bufferSize)
{
if (bufferCount <= 0 || bufferSize <= 0) {
HDF_LOGE("UseBufferOnPort bufferCount <= 0 or bufferSize <= 0");
return HDF_ERR_INVALID_PARAM;
}
for (int i = 0; i < bufferCount; i++) {
OmxCodecBuffer *omxBuffer = new OmxCodecBuffer();
memset_s(omxBuffer, sizeof(OmxCodecBuffer), 0, sizeof(OmxCodecBuffer));
std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
omxBuffer->size = sizeof(OmxCodecBuffer);
omxBuffer->version.s.nVersionMajor = 1;
omxBuffer->bufferType = BUFFER_TYPE_AVSHARE_MEM_FD;
omxBuffer->bufferType = CODEC_BUFFER_TYPE_AVSHARE_MEM_FD;
int fd = AshmemCreate(0, bufferSize);
shared_ptr<Ashmem> sharedMem = make_shared<Ashmem>(fd, bufferSize);
omxBuffer->bufferLen = FD_SIZE;
omxBuffer->buffer = (uint8_t *)(unsigned long)fd;
omxBuffer->fd = fd;
omxBuffer->bufferhandle = nullptr;
omxBuffer->allocLen = bufferSize;
omxBuffer->fenceFd = -1;
omxBuffer->pts = 0;
omxBuffer->flag = 0;
if (portIndex == PortIndex::PORT_INDEX_INPUT) {
omxBuffer->type = READ_ONLY_TYPE; // ReadOnly
......@@ -444,84 +464,75 @@ bool CodecHdiDecode::UseBufferOnPort(enum PortIndex portIndex, int bufferCount,
omxBuffer->type = READ_WRITE_TYPE;
sharedMem->MapReadOnlyAshmem();
}
auto err = client_->UseBuffer(client_, (uint32_t)portIndex, omxBuffer);
OmxCodecBuffer outBuffer;
auto err = client_->UseBuffer((uint32_t)portIndex, *omxBuffer.get(), outBuffer);
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed to UseBuffer with portIndex[%{public}d]", __func__, portIndex);
sharedMem->UnmapAshmem();
sharedMem->CloseAshmem();
sharedMem = nullptr;
return false;
return err;
}
omxBuffer->bufferLen = 0;
omxBuffer->bufferId = outBuffer.bufferId;
omxBuffer->fd = -1;
HDF_LOGI("UseBuffer returned bufferID [%{public}d]", omxBuffer->bufferId);
BufferInfo *bufferInfo = new BufferInfo;
std::shared_ptr<BufferInfo> bufferInfo = std::make_shared<BufferInfo>();
bufferInfo->omxBuffer = omxBuffer;
bufferInfo->avSharedPtr = sharedMem;
bufferInfo->portIndex = portIndex;
omxBuffers_.insert(std::make_pair<int, BufferInfo *>(omxBuffer->bufferId, std::move(bufferInfo)));
omxBuffers_.emplace(std::make_pair(omxBuffer->bufferId, bufferInfo));
if (portIndex == PortIndex::PORT_INDEX_INPUT) {
unUsedInBuffers_.push_back(omxBuffer->bufferId);
} else {
unUsedOutBuffers_.push_back(omxBuffer->bufferId);
}
int fdret = (int)omxBuffer->buffer;
HDF_LOGI("{bufferID = %{public}d, srcfd = %{public}d, retfd = %{public}d}", omxBuffer->bufferId, fd, fdret);
}
return true;
return HDF_SUCCESS;
}
```
#### 编解码Buffer流转
用户需要先将组件设置为OMX_StateExecuting状态,然后填充输入buffer,读取输出buffer,进行buffer的轮转。
用户需要先将组件设置为CODEC_STATE_EXECUTING状态,然后填充输入buffer,读取输出buffer,进行buffer的轮转。
```cpp
// 设置组件进入OMX_StateExecuting状态并开始buffer的轮转
HDF_LOGI("...command to OMX_StateExecuting....");
auto err = client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateExecuting, NULL, 0);
HDF_LOGI("...command to CODEC_STATE_EXECUTING....");
auto err = client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_EXECUTING, {});
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s failed to SendCommand with OMX_CommandStateSet:OMX_StateIdle", __func__);
HDF_LOGE("%{public}s failed to SendCommand with CODEC_COMMAND_STATE_SET:CODEC_STATE_IDLE", __func__);
return;
}
// 设置输出buffer填充
for (auto bufferId : unUsedOutBuffers_) {
HDF_LOGI("fill bufferid [%{public}d]", bufferId);
auto iter = omxBuffers_.find(bufferId);
if (iter != omxBuffers_.end()) {
BufferInfo *bufferInfo = iter->second;
auto err = client_->FillThisBuffer(client_, bufferInfo->pOmxBuffer);
if (err != HDF_SUCCESS) {
HDF_LOGE("FillThisBuffer error");
FUNC_EXIT_ERR();
if (!FillAllTheBuffer()) {
HDF_LOGE("%{public}s FillAllTheBuffer error", __func__);
return;
}
}
}
// 填充输入buffer
bool bEndOfFile = false;
while (!bEndOfFile) {
int bufferID = GetFreeBufferId();
auto t1 = std::chrono::system_clock::now();
bool eosFlag = false;
while (!eosFlag) {
if (this->exit_) {
break;
}
int bufferID = GetFreeBufferId();
if (bufferID < 0) {
usleep(10000);
usleep(10000); // 10000 for wait 10ms
continue;
}
auto iter = omxBuffers_.find(bufferID);
if (iter == omxBuffers_.end()) {
continue;
}
BufferInfo *bufferInfo = iter->second;
void *sharedAddr = (void *)bufferInfo->avSharedPtr->ReadFromAshmem(0, 0);
bool bEOS = (size_t)this->ReadOnePacket(fpIn_, (char *)sharedAddr, bufferInfo->omxBuffer->filledLen);
HDF_LOGI("read data size is %{public}d", bufferInfo->omxBuffer->filledLen);
auto bufferInfo = iter->second;
void *sharedAddr = const_cast<void *>(bufferInfo->avSharedPtr->ReadFromAshmem(0, 0));
eosFlag = this->ReadOnePacket(fpIn_, static_cast<char *>(sharedAddr), bufferInfo->omxBuffer->filledLen);
bufferInfo->omxBuffer->offset = 0;
if (bEOS) {
if (eosFlag) {
bufferInfo->omxBuffer->flag = OMX_BUFFERFLAG_EOS;
bEndOfFile = true;
}
auto err = client_->EmptyThisBuffer(client_, bufferInfo->omxBuffer);
err = client_->EmptyThisBuffer(*bufferInfo->omxBuffer.get());
if (err != HDF_SUCCESS) {
HDF_LOGE("%{public}s EmptyThisBuffer error", __func__);
return;
......@@ -529,180 +540,186 @@ while (!bEndOfFile) {
}
// wait
while (!this->exit_) {
usleep(10000);
continue;
usleep(10000); // 10000 for wait 10ms
}
// 解码完成后使组件进入OMX_StateIdle状态
client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateIdle, NULL, 0);
auto t2 = std::chrono::system_clock::now();
std::chrono::duration<double> diff = t2 - t1;
HDF_LOGI("cost %{public}f, count=%{public}d", diff.count(), count_);
(void)client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_IDLE, {});
return;
}
```
当在rk开发板上进行解码时,由于其OMX的实现不支持数据的分帧,所以需要手动分帧,目前简单实现按照起始码0x000001或0x00000001分帧发送到服务端处理。分帧代码如下:
```cpp
// 文件分帧读取实现
bool OMXCore::ReadOnePacket(FILE* fp, char* buf, uint32_t& nFilled)
bool CodecHdiDecode::ReadOnePacket(FILE *fp, char *buf, uint32_t &filledCount)
{
// 先读取4个字节
size_t t = fread(buf, 1, 4, fp);
if (t < 4) {
// 文件读取结束
// 读取起始码
size_t t = fread(buf, 1, START_CODE_SIZE_FRAME, fp);
if (t < START_CODE_SIZE_FRAME) {
return true;
}
size_t filled = 0;
filled = 4;
bool bRet = true;
char *temp = buf;
temp += START_CODE_SIZE_FRAME;
bool ret = true;
while (!feof(fp)) {
fread(buf + filled, 1, 1, fp);
if (buf[filled] == 1) {
(void)fread(temp, 1, 1, fp);
if (*temp != START_CODE) {
temp++;
continue;
}
// 检查起始码
if ((buf[filled - 1] == 0) &&
(buf[filled - 2] == 0) &&
(buf[filled - 3] == 0)) {
fseek(fp, -4, SEEK_CUR);
filled -= 3;
bRet = false;
break;
} else if ((buf[filled - 1] == 0) &&
(buf[filled - 2] == 0)) {
fseek(fp, -3, SEEK_CUR);
filled -= 2;
bRet = false;
if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0) &&
(temp[START_CODE_OFFSET_THIRD] == 0)) {
fseek(fp, -START_CODE_SIZE_FRAME, SEEK_CUR);
temp -= (START_CODE_SIZE_FRAME - 1);
ret = false;
break;
}
if ((temp[START_CODE_OFFSET_ONE] == 0) && (temp[START_CODE_OFFSET_SEC] == 0)) {
fseek(fp, -START_CODE_SIZE_SLICE, SEEK_CUR);
temp -= (START_CODE_SIZE_SLICE - 1);
ret = false;
break;
}
filled++;
temp++;
}
nFilled = filled;
return bRet;
filledCount = (temp - buf);
return ret;
}
```
Codec HDI提供3个回调函数:EventHandler,EmptyBufferDone和FillBufferDone。
- EventHandler:主要命令完成后的通知,例如:OMX_StateIdle转为OMX_StateExecuting的命令执行成功通知等。
- EventHandler:主要命令完成后的通知,例如:CODEC_STATE_IDLE转为CODEC_STATE_EXECUTING的命令执行成功通知等。
- EmptyBufferDone:输入数据消费完毕,客户端需要重新填入待编解码数据,再次调用EmptyThisBuffer。
- FillBufferDone:输出数据填充完毕,客户端需要读取已编码/解码数据,再次调用FillThisBuffer。
```cpp
// EmptyBufferDone回调处理示例
int32_t OMXCore::OnEmptyBufferDone(struct CodecCallbackType *self, int8_t *pAppData, uint32_t pAppDataLen,
const struct OmxCodecBuffer *pBuffer)
{
HDF_LOGI("onEmptyBufferDone: pBuffer.bufferID [%{public}d]", pBuffer->bufferId);
g_core->OnEmptyBufferDone(pBuffer);
return HDF_SUCCESS;
}
int32_t OMXCore::OnEmptyBufferDone(const struct OmxCodecBuffer *pBuffer)
int32_t CodecHdiDecode::OnEmptyBufferDone(const struct OmxCodecBuffer &buffer)
{
unique_lock<mutex> ulk(mLockInputBuffers_);
unUsedInBuffers_.push_back(pBuffer->bufferId);
HDF_LOGI("OnEmptyBufferDone, bufferId [%{public}d]", buffer.bufferId);
unique_lock<mutex> ulk(lockInputBuffers_);
unUsedInBuffers_.push_back(buffer.bufferId);
return HDF_SUCCESS;
}
// FillBufferDone回调处理示例
int32_t OMXCore::OnFillBufferDone(struct CodecCallbackType *self, int8_t *pAppData, uint32_t pAppDataLen,
struct OmxCodecBuffer *pBuffer)
int32_t CodecHdiDecode::OnFillBufferDone(const struct OmxCodecBuffer &buffer)
{
HDF_LOGI("onFillBufferDone: pBuffer.bufferID [%{public}d]", pBuffer->bufferId);
g_core->OnFillBufferDone(pBuffer);
return HDF_SUCCESS;
}
int32_t OMXCore::onFillBufferDone(struct OmxCodecBuffer* pBuffer)
{
// 根据bufferID找到buffer
if (bExit_) {
HDF_LOGI("OnFillBufferDone, bufferId [%{public}d]", buffer.bufferId);
if (exit_) {
return HDF_SUCCESS;
}
auto iter = omxBuffers_.find(pBuffer->bufferId);
if (iter == omxBuffers_.end() || !iter->second) {
auto iter = omxBuffers_.find(buffer.bufferId);
if ((iter == omxBuffers_.end()) || (iter->second == nullptr)) {
return HDF_SUCCESS;
}
// 取出输出的数据
BufferInfo *pBufferInfo = iter->second;
const void *addr = pBufferInfo->avSharedPtr->ReadFromAshmem(pBuffer->filledLen, pBuffer->offset);
// 解码数据保存到文件
fwrite(addr, 1, pBuffer->filledLen, fpOut_.get());
fflush(fpOut_.get());
// 重置buffer数据
pBuffer->offset = 0;
pBuffer->filledLen = 0;
if (pBuffer->flag == OMX_BUFFERFLAG_EOS) {
// 结束
bExit_ = true;
count_++;
// read buffer
auto bufferInfo = iter->second;
if (bufferInfo->avSharedPtr != nullptr) {
const void *addr = bufferInfo->avSharedPtr->ReadFromAshmem(buffer.filledLen, buffer.offset);
(void)fwrite(addr, 1, buffer.filledLen, fpOut_);
} else if (bufferInfo->bufferHandle != nullptr && gralloc_ != nullptr) {
gralloc_->Mmap(*bufferInfo->bufferHandle);
(void)fwrite(bufferInfo->bufferHandle->virAddr, 1, buffer.filledLen, fpOut_);
gralloc_->Unmap(*bufferInfo->bufferHandle);
}
(void)fflush(fpOut_);
if (buffer.flag == OMX_BUFFERFLAG_EOS) {
// end
exit_ = true;
HDF_LOGI("OnFillBufferDone the END coming");
return HDF_SUCCESS;
}
// 再次调用FillThisBuffer
auto err = client_->FillThisBuffer(client_, pBufferInfo->pOmxBuffer);
// call fillthisbuffer again
auto err = client_->FillThisBuffer(*bufferInfo->omxBuffer.get());
if (err != HDF_SUCCESS) {
HDF_LOGE("FillThisBuffer error");
HDF_LOGE("%{public}s FillThisBuffer error", __func__);
return HDF_SUCCESS;
}
return HDF_SUCCESS;
}
// EventHandler示例
int32_t CodecHdiDecode::OnEvent(struct CodecCallbackType *self, enum OMX_EVENTTYPE event, struct EventInfo *info)
int32_t CodecHdiDecode::EventHandler(CodecEventType event, const EventInfo &info)
{
HDF_LOGI("onEvent: appData[0x%{public}p], eEvent [%{public}d], "
"nData1[%{public}d]", info->appData, event, info->data1);
switch (event) {
case OMX_EventCmdComplete: {
OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE)info->data1;
if (OMX_CommandStateSet == cmd) {
HDF_LOGI("OMX_CommandStateSet reached, status is %{public}d", info->data2);
g_core->onStatusChanged();
case CODEC_EVENT_CMD_COMPLETE: {
CodecCommandType cmd = (CodecCommandType)info.data1;
if (CODEC_COMMAND_STATE_SET == cmd) {
HDF_LOGI("CODEC_COMMAND_STATE_SET reached, status is %{public}d", info.data2);
this->OnStatusChanged();
}
break;
}
case OMX_EventPortSettingsChanged: {
HDF_LOGI("OMX_EventPortSeetingsChanged reached");
this->HandleEventPortSettingsChanged(info.data1, info.data2);
}
default:
break;
}
return HDF_SUCCESS;
}
```
#### 接口去初始化
组件关闭前,需要将组件状态修改为OMX_StateIdle,然后开始释放输入输出Buffer,再将组件状态修改为OMX_StateLoaded,最后再调用DestoryComponent去关闭组件。
组件关闭前,需要将组件状态修改为CODEC_STATE_IDLE,然后开始释放输入输出Buffer,再将组件状态修改为CODEC_STATE_LOADED,最后再调用DestoryComponent去关闭组件。
##### Buffer释放示例
```cpp
// 发送命令使组件进入OMX_StateLoaded状态
client_->SendCommand(client_, OMX_CommandStateSet, OMX_StateLoaded, nullptr, 0);
client_->SendCommand(CODEC_COMMAND_STATE_SET, CODEC_STATE_LOADED, {});
// 释放所有申请的buffer
auto iter = omxBuffers_.begin();
while (iter != omxBuffers_.end()) {
BufferInfo *bufferInfo = iter->second;
client_->FreeBuffer(client_, (uint32_t)bufferInfo->portIndex, bufferInfo->omxBuffer);
delete bufferInfo;
iter++;
auto bufferInfo = iter->second;
iter = omxBuffers_.erase(iter);
(void)client_->FreeBuffer((uint32_t)bufferInfo->portIndex, *bufferInfo->omxBuffer.get());
bufferInfo = nullptr;
}
omxBuffers_.clear();
unUsedInBuffers_.clear();
unUsedOutBuffers_.clear();
enum OMX_STATETYPE status;
client_->GetState(client_, &status);
// buffer释放后组件即进入OMX_StateLoaded状态
if (status != OMX_StateLoaded) {
CodecStateType status = CODEC_STATE_INVALID;
int32_t err = HDF_SUCCESS;
int32_t tryCount = 3;
do {
err = client_->GetState(status);
if (err != HDF_SUCCESS) {
HDF_LOGE("%s GetState error [%{public}x]", __func__, err);
break;
}
if (status != CODEC_STATE_LOADED) {
HDF_LOGI("Wait for OMX_StateLoaded status");
this->WaitForStatusChanged();
} else {
HDF_LOGI(" status is %{public}d", status);
}
}
tryCount--;
} while ((status != CODEC_STATE_LOADED) && (tryCount > 0));
```
##### 组件实例释放示例
```cpp
// 组件实例释放
void OMXCore::Release() {
omxMgr_->DestoryComponent(client_);
void CodecHdiDecode::Release()
{
omxMgr_->DestoryComponent(componentId_);
client_ = nullptr;
CodecComponentManagerRelease();
callback_ = nullptr;
omxMgr_ = nullptr;
}
```
......@@ -747,7 +764,6 @@ OpenMax对AVCC格式的数据处理,第一帧一定要是extra_data,可能
1. 输出端口的xFramerate参数未正常设置。
2. 如果设置了参数OMX_VIDEO_PARAM_AVCTYPE,请检查此参数是否正确。
**解决办法**
请看编码时codec_host的日志,搜索“encode params init settings”,确认是否出现异常的参数。如果是framerate为0,则是原因1,需要将正常的framerate左移16位;如果是其它参数异常,可能是原因2,需要检查其相应的参数。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册