上一节我们了解了 OMXNodeInstance 的创建过程,以及 IOmx 服务和 OMXNodeInstance、OMX组件之间的联系。这一节我们将一起了解 ACodec 是如何通过 OMXNodeInstance 这个中间层进行端口定义设置,以及端口Buffer分配的。
OMXNodeInstance 的代码还是比较长的,我们需要重点抓住和 Buffer 相关的内容,也就是端口定义、Buffer分配以及 Buffer 传递,了解了 Buffer 那我们对 OpenMax 的学习就会很轻松了。
我们之前在学习 ACodec configureCodec 流程时看到有很多 portMode,端口类型确定之后就会调用 setPortMode 方法将端口模式设定给 OMXNode,最终设置给 OMX 组件。
status_t ACodec::setPortMode(int32_t portIndex, IOMX::PortMode mode) {
status_t err = mOMXNode->setPortMode(portIndex, mode);
if (err != OK) {
ALOGE("[%s] setPortMode on %s to %s failed w/ err %d",
mComponentName.c_str(),
portIndex == kPortIndexInput ? "input" : "output",
asString(mode),
err);
return err;
}
mPortMode[portIndex] = mode;
return OK;
}
OMXNodeInstance 会根据设定的内容对 OMX 组件进行配置,我们这里暂时只研究解码的情况,一般解码流程可能会涉及到如下几种 port Mode:
in Port
out Port
之前我们讲过,Preset 是预设的意思,表示这块buffer是预先分配好的,之后使用过程中就不会发生变化了;ByteBuffer 指的是普通的buffer,我们通过指针就可以读写buffer中的内容。
kPortModePresetByteBuffer 会在两个情况下使用:
这两种情况下是可以通过指针读写 buffer 中内容的,也就意味着内容是不受保护的。
status_t OMXNodeInstance::setPortMode(OMX_U32 portIndex, IOMX::PortMode mode) {
case IOMX::kPortModePresetByteBuffer:
{
// Disable secure buffer, native buffer and metadata.
(void)enableNativeBuffers_l(portIndex, OMX_TRUE /*graphic*/, OMX_FALSE);
(void)enableNativeBuffers_l(portIndex, OMX_FALSE /*graphic*/, OMX_FALSE);
(void)storeMetaDataInBuffers_l(portIndex, OMX_FALSE, NULL);
break;
}
}
从注释中我们可以看出来,需要关闭端口的 secure buffer,native buffer以及metadata功能,这里的native buffer指的应该就是graphic buffer。
从这里我们可以猜测,OMX 组件端口使用的buffer可能有3种,默认使用普通buffer:
使用普通 buffer 就要把另外两个配置关闭,这里可以通过enableNativeBuffers_l
方法来完成,之所以通过一个方法(并且方法名为 native buffer),是因为这些buffer本身都应该是由 native 层分配。由于OMXNodeInstance 把 secure buffer, graphic buffer的设置放到一起了,所以enableNativeBuffers_l容易把人看晕,把他拆成两部分:
先看 native buffer(graphic buffer)的配置部分,除了调用OMX_SetParameter对组件进行设定外,还将 mGraphicBufferEnabled
数组置为了 true/false,用于标记端口是否使用graphic buffer,如果使用了就置为true,没有使用就置为false。
OMX_STRING name = "OMX.google.android.index.enableAndroidNativeBuffers"
EnableAndroidNativeBuffersParams params;
InitOMXParams(¶ms);
params.nPortIndex = portIndex;
params.enable = enable;
err = OMX_SetParameter(mHandle, index, ¶ms);
CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
portString(portIndex), portIndex, enable);
if (err == OMX_ErrorNone) {
mGraphicBufferEnabled[portIndex] = enable;
} else if (enable) {
mGraphicBufferEnabled[portIndex] = false;
}
再看 secure buffer 的配置部分,secure buffer 对应的配置名称为 native handle,这是因为native层分配的buffer会以handle的形式回传上层,从而保护buffer。
OMX_STRING name = "OMX.google.android.index.allocateNativeHandle"
EnableAndroidNativeBuffersParams params;
InitOMXParams(¶ms);
params.nPortIndex = portIndex;
params.enable = enable;
err = OMX_SetParameter(mHandle, index, ¶ms);
CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
portString(portIndex), portIndex, enable);
if (!graphic) {
if (err == OMX_ErrorNone) {
mSecureBufferType[portIndex] =
enable ? kSecureBufferTypeNativeHandle : kSecureBufferTypeOpaque;
} else if (mSecureBufferType[portIndex] == kSecureBufferTypeUnknown) {
mSecureBufferType[portIndex] = kSecureBufferTypeOpaque;
}
}
如果 secure buffer 设置成功,那么 mSecureBufferType
会被设置为 kSecureBufferTypeNativeHandle,否则置为 kSecureBufferTypeOpaque。
我们这里大概知道:
除了以上两项配置外,还有额外的meta data type需要配置,我们前面了解过graphic buffer需要和metadata 搭配使用,但是metadata也有不同的类型,我们需要告知 OMX 组件使用哪一种 metaData:
status_t OMXNodeInstance::storeMetaDataInBuffers_l(
OMX_U32 portIndex, OMX_BOOL enable, MetadataBufferType *type) {
OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
"OMX.google.android.index.storeMetaDataInBuffers");
OMX_STRING nativeBufferName = const_cast<OMX_STRING>(
"OMX.google.android.index.storeANWBufferInMetadata");
MetadataBufferType negotiatedType;
MetadataBufferType requestedType = type != NULL ? *type : kMetadataBufferTypeANWBuffer;
StoreMetaDataInBuffersParams params;
InitOMXParams(¶ms);
params.nPortIndex = portIndex;
params.bStoreMetaData = enable;
OMX_ERRORTYPE err =
requestedType == kMetadataBufferTypeANWBuffer
? OMX_GetExtensionIndex(mHandle, nativeBufferName, &index)
: OMX_ErrorUnsupportedIndex;
OMX_ERRORTYPE xerr = err;
if (err == OMX_ErrorNone) {
err = OMX_SetParameter(mHandle, index, ¶ms);
if (err == OMX_ErrorNone) {
name = nativeBufferName; // set name for debugging
negotiatedType = requestedType;
}
}
if (err != OMX_ErrorNone) {
err = OMX_GetExtensionIndex(mHandle, name, &index);
xerr = err;
if (err == OMX_ErrorNone) {
negotiatedType =
requestedType == kMetadataBufferTypeANWBuffer
? kMetadataBufferTypeGrallocSource : requestedType;
err = OMX_SetParameter(mHandle, index, ¶ms);
}
if (err == OMX_ErrorBadParameter) {
err = OMX_ErrorUnsupportedIndex;
}
}
...
else {
if (!enable) {
negotiatedType = kMetadataBufferTypeInvalid;
}
mMetadataType[portIndex] = negotiatedType;
}
if (type != NULL) {
*type = negotiatedType;
}
return StatusFromOMXError(err);
}
storeMetaDataInBuffers_l 的代码比较长,但是我们只要知道,使用graphic buffer做output时,metaData使用的类型是 kMetadataBufferTypeANWBuffer
,这个值会被记录到 mMetadataType
中。如果不使用 metaData,那 mMetadataType 将会被设置为 kMetadataBufferTypeInvalid
。