#define OMX_FillThisBuffer (
hComponent,
pBuffer
)
((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer(
hComponent,
pBuffer)
作用:向组件的输出端口发送空白buffer
status_t ACodec::allocateOutputBuffersFromNativeWindow() {
// This method only handles the non-metadata mode (or simulating legacy
// mode with metadata, which is transparent to ACodec).
CHECK(!storingMetadataInDecodedBuffers());
OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers;
status_t err = configureOutputBuffersFromNativeWindow(
&bufferCount, &bufferSize, &minUndequeuedBuffers, true /* preregister */);
if (err != 0)
return err;
mNumUndequeuedBuffers = minUndequeuedBuffers;
static_cast<Surface*>(mNativeWindow.get())
->getIGraphicBufferProducer()->allowAllocation(true);
ALOGV("[%s] Allocating %u buffers from a native window of size %u on "
"output port",
mComponentName.c_str(), bufferCount, bufferSize);
// Dequeue buffers and send them to OMX
for (OMX_U32 i = 0; i < bufferCount; i++) {
ANativeWindowBuffer *buf;
int fenceFd;
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd);
if (err != 0) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);
break;
}
sp<GraphicBuffer> graphicBuffer(GraphicBuffer::from(buf));
BufferInfo info;
info.mStatus = BufferInfo::OWNED_BY_US;
info.mFenceFd = fenceFd;
info.mIsReadFence = false;
info.mRenderInfo = NULL;
info.mGraphicBuffer = graphicBuffer;
info.mNewGraphicBuffer = false;
info.mDequeuedAt = mDequeueCounter;
// TODO: We shouln't need to create MediaCodecBuffer. In metadata mode
// OMX doesn't use the shared memory buffer, but some code still
// access info.mData. Create an ABuffer as a placeholder.
info.mData = new MediaCodecBuffer(mOutputFormat, new ABuffer(bufferSize));
info.mCodecData = info.mData;
mBuffers[kPortIndexOutput].push(info);
IOMX::buffer_id bufferId;
err = mOMXNode->useBuffer(kPortIndexOutput, graphicBuffer, &bufferId);
if (err != 0) {
ALOGE("registering GraphicBuffer %u with OMX IL component failed: "
"%d", i, err);
break;
}
mBuffers[kPortIndexOutput].editItemAt(i).mBufferID = bufferId;
ALOGV("[%s] Registered graphic buffer with ID %u (pointer = %p)",
mComponentName.c_str(),
bufferId, graphicBuffer.get());
}
OMX_U32 cancelStart;
OMX_U32 cancelEnd;
if (err != OK) {
// If an error occurred while dequeuing we need to cancel any buffers
// that were dequeued. Also cancel all if we're in legacy metadata mode.
cancelStart = 0;
cancelEnd = mBuffers[kPortIndexOutput].size();
} else {
// Return the required minimum undequeued buffers to the native window.
cancelStart = bufferCount - minUndequeuedBuffers;
cancelEnd = bufferCount;
}
for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {
BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
if (info->mStatus == BufferInfo::OWNED_BY_US) {
status_t error = cancelBufferToNativeWindow(info);
if (err == 0) {
err = error;
}
}
}
static_cast<Surface*>(mNativeWindow.get())
->getIGraphicBufferProducer()->allowAllocation(false);
return err;
}
从显示那边拿到buffer后对mBuffers[kPortIndexOutput]进行填充
status_t ACodec::fillBuffer(BufferInfo *info) {
status_t err;
// Even in dynamic ANW buffer mode, if the graphic buffer is not changing,
// send sPreset instead of the same graphic buffer, so that OMX server
// side doesn't update the meta. In theory it should make no difference,
// however when the same buffer is parcelled again, a new handle could be
// created on server side, and some decoder doesn't recognize the handle
// even if it's the same buffer.
if (!storingMetadataInDecodedBuffers() || !info->mNewGraphicBuffer) {
err = mOMXNode->fillBuffer(
info->mBufferID, OMXBuffer::sPreset, info->mFenceFd);
} else {
err = mOMXNode->fillBuffer(
info->mBufferID, info->mGraphicBuffer, info->mFenceFd);
}
info->mNewGraphicBuffer = false;
info->mFenceFd = -1;
if (err == OK) {
info->mStatus = BufferInfo::OWNED_BY_COMPONENT;
}
return err;
}
status_t OMXNodeInstance::fillBuffer(
IOMX::buffer_id buffer, const OMXBuffer &omxBuffer, int fenceFd) {
Mutex::Autolock autoLock(mLock);
if (mHandle == NULL) {
return DEAD_OBJECT;
}
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexOutput);
if (header == NULL) {
ALOGE("b/25884056");
return BAD_VALUE;
}
if (omxBuffer.mBufferType == OMXBuffer::kBufferTypeANWBuffer) {
status_t err = updateGraphicBufferInMeta_l(
kPortIndexOutput, omxBuffer.mGraphicBuffer, buffer, header);
if (err != OK) {
CLOG_ERROR(fillBuffer, err, FULL_BUFFER(
(intptr_t)header->pBuffer, header, fenceFd));
return err;
}
} else if (omxBuffer.mBufferType != OMXBuffer::kBufferTypePreset) {
return BAD_VALUE;
}
header->nFilledLen = 0;
header->nOffset = 0;
header->nFlags = 0;
// meta now owns fenceFd
status_t res = storeFenceInMeta_l(header, fenceFd, kPortIndexOutput);
if (res != OK) {
CLOG_ERROR(fillBuffer::storeFenceInMeta, res, EMPTY_BUFFER(buffer, header, fenceFd));
return res;
}
{
Mutex::Autolock _l(mDebugLock);
mOutputBuffersWithCodec.add(header);
CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header, fenceFd)));
}
OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
if (err != OMX_ErrorNone) {
CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header, fenceFd));
Mutex::Autolock _l(mDebugLock);
mOutputBuffersWithCodec.remove(header);
}
return StatusFromOMXError(err);
}
pOMXComponent->FillThisBuffer = &xxx_OMX_FillThisBuffer;
在对应的插件中实现此函数