Android MediaCodec OMX_FillThisBuffer流程分析

OMX_FillThisBuffer
#define OMX_FillThisBuffer (
hComponent,
pBuffer
)
((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer(
hComponent,
pBuffer)

作用:向组件的输出端口发送空白buffer

allocateOutputBuffersFromNativeWindow
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]进行填充

fillBuffer
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);
}

xxx_OMX_FillThisBuffer
pOMXComponent->FillThisBuffer  = &xxx_OMX_FillThisBuffer;

在对应的插件中实现此函数

你可能感兴趣的:(Android,android,FillThisBuffer)