OMXCodec源码分析---part2

来源:互联网 发布:工程量清单软件 编辑:程序博客网 时间:2024/06/05 11:10

书接前文

omxcodec创建完了以后,后面就要开始读取数据,解码,送出数据一系列的操作

接着看initvideodecoder,create omxcodec以后,调用了strat方法,代码如下

{    CODEC_LOGV("OMXCodec::start ");    Mutex::Autolock autoLock(mLock);    if (mState != LOADED) {        return UNKNOWN_ERROR;    }    sp<MetaData> params = new MetaData;    if (mQuirks & kWantsNALFragments) {        params->setInt32(kKeyWantsNALFragments, true);    }    if (meta) {        int64_t startTimeUs = 0;        int64_t timeUs;        if (meta->findInt64(kKeyTime, &timeUs)) {            startTimeUs = timeUs;        }        params->setInt64(kKeyTime, startTimeUs);    }    status_t err = mSource->start(params.get());    if (err != OK) {        return err;    }    mCodecSpecificDataIndex = 0;    mInitialBufferSubmit = true;    mSignalledEOS = false;    mNoMoreOutputData = false;    mOutputPortSettingsHaveChanged = false;    mSeekTimeUs = -1;    mSeekMode = ReadOptions::SEEK_CLOSEST_SYNC;    mTargetTimeUs = -1;    mFilledBuffers.clear();    mPaused = false;    err = init();    if (err != OK) {        ALOGV("init failed, so stop source");        mSource->stop();    }    return err;}

初始化一些参数,init函数接着看

{    // mLock is held.    CHECK_EQ((int)mState, (int)LOADED);    status_t err;    if (!(mQuirks & kRequiresLoadedToIdleAfterAllocation)) {        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);        setState(LOADED_TO_IDLE);    }    err = allocateBuffers();    if (err != (status_t)OK) {        return err;    }    if (mQuirks & kRequiresLoadedToIdleAfterAllocation) {        err = mOMX->sendCommand(mNode, OMX_CommandStateSet, OMX_StateIdle);        CHECK_EQ(err, (status_t)OK);        setState(LOADED_TO_IDLE);    }    while (mState != EXECUTING && mState != ERROR) {mAsyncCompletion.wait(mLock);    }    return mState == ERROR ? UNKNOWN_ERROR : OK;}

omxcodec有一些状态的转换,然后就是allocateBuffers这个函数了

{    if (mNativeWindow != NULL && portIndex == kPortIndexOutput) {        return allocateOutputBuffersFromNativeWindow();    }    if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {        ALOGE("protected output buffers must be stent to an ANativeWindow");        return PERMISSION_DENIED;    }    status_t err = OK;    if ((mFlags & kStoreMetaDataInVideoBuffers)            && portIndex == kPortIndexInput) {        err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);        if (err != OK) {            ALOGE("Storing meta data in video buffers is not supported");            return err;        }    }    OMX_PARAM_PORTDEFINITIONTYPE def;    InitOMXParams(&def);    def.nPortIndex = portIndex;    err = mOMX->getParameter(            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));    if (err != OK) {        return err;    }    size_t totalSize = def.nBufferCountActual * def.nBufferSize;    mDealer[portIndex] = new MemoryDealer(totalSize, "OMXCodec");    for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) {        sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize);        CHECK(mem.get() != NULL);        BufferInfo info;        info.mData = NULL;        info.mSize = def.nBufferSize;        IOMX::buffer_id buffer;        if (portIndex == kPortIndexInput                && ((mQuirks & kRequiresAllocateBufferOnInputPorts)                    || (mFlags & kUseSecureInputBuffers))) {            if (mOMXLivesLocally) {                mem.clear();                err = mOMX->allocateBuffer(                        mNode, portIndex, def.nBufferSize, &buffer,                        &info.mData);            } else {                err = mOMX->allocateBufferWithBackup(                        mNode, portIndex, mem, &buffer);            }        } else if (portIndex == kPortIndexOutput                && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {            if (mOMXLivesLocally) {                mem.clear();                err = mOMX->allocateBuffer(                        mNode, portIndex, def.nBufferSize, &buffer,                        &info.mData);            } else {                err = mOMX->allocateBufferWithBackup(                        mNode, portIndex, mem, &buffer);            }        } else {            err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);        }        if (err != OK) {            ALOGE("allocate_buffer_with_backup failed");            return err;        }        if (mem != NULL) {            info.mData = mem->pointer();        }        info.mBuffer = buffer;        info.mStatus = OWNED_BY_US;        info.mMem = mem;        info.mMediaBuffer = NULL;        if (portIndex == kPortIndexOutput) {            if (!(mOMXLivesLocally                        && (mQuirks & kRequiresAllocateBufferOnOutputPorts)                        && (mQuirks & kDefersOutputBufferAllocation))) {                // If the node does not fill in the buffer ptr at this time,                // we will defer creating the MediaBuffer until receiving                // the first FILL_BUFFER_DONE notification instead.                info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize);                info.mMediaBuffer->setObserver(this);            }        }        mPortBuffers[portIndex].push(info);        CODEC_LOGV("allocated buffer %p on %s port", buffer,             portIndex == kPortIndexInput ? "input" : "output");    }    if (portIndex == kPortIndexOutput) {        sp<MetaData> meta = mSource->getFormat();        int32_t delay = 0;        if (!meta->findInt32(kKeyEncoderDelay, &delay)) {            delay = 0;        }        int32_t padding = 0;        if (!meta->findInt32(kKeyEncoderPadding, &padding)) {            padding = 0;        }        int32_t numchannels = 0;        if (delay + padding) {            if (mOutputFormat->findInt32(kKeyChannelCount, &numchannels)) {                size_t frameSize = numchannels * sizeof(int16_t);                if (mSkipCutBuffer != NULL) {                    size_t prevbuffersize = mSkipCutBuffer->size();                    if (prevbuffersize != 0) {                        ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbuffersize);                    }                }                mSkipCutBuffer = new SkipCutBuffer(delay * frameSize, padding * frameSize);            }        }    }    // dumpPortStatus(portIndex);    if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {        Vector<MediaBuffer *> buffers;        for (size_t i = 0; i < def.nBufferCountActual; ++i) {            const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);            MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);            buffers.push(mbuf);        }        status_t err = mSource->setBuffers(buffers);        if (err != OK) {            for (size_t i = 0; i < def.nBufferCountActual; ++i) {                buffers.editItemAt(i)->release();            }            buffers.clear();            CODEC_LOGE(                    "Codec requested to use secure input buffers but "                    "upstream source didn't support that.");            return err;        }    }    return OK;}

这个函数挺重要的,omx node是通过port来通信的,inport和output,输入node只有inport,而输出node就只有outport,中间解码的node就需要两个port

先看inport的内存分配,有两个函数 allocatebuffer 和 usebuffer,如果不需要node重新分配内存,那就只需要使用application分配的内存,否则会在port上面重新分配内存

为什么需要再port上面重新分配内存呢,可能是DRM等原因考虑。

在看一下outport的分配

{    // Get the number of buffers needed.    OMX_PARAM_PORTDEFINITIONTYPE def;    InitOMXParams(&def);    def.nPortIndex = kPortIndexOutput;    status_t err = mOMX->getParameter(            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));    if (err != OK) {        return err;    }    err = native_window_set_buffers_geometry(            mNativeWindow.get(),            def.format.video.nFrameWidth,            def.format.video.nFrameHeight,            def.format.video.eColorFormat);    if (err != 0) {        ALOGE("native_window_set_buffers_geometry failed: %s (%d)",                strerror(-err), -err);        return err;    }    initNativeWindowCrop();    err = applyRotation();    if (err != OK) {        return err;    }    // Set up the native window.    OMX_U32 usage = 0;    err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage);    if (err != 0) {        ALOGW("querying usage flags from OMX IL component failed: %d", err);        // XXX: Currently this error is logged, but not fatal.        usage = 0;    }    if (mFlags & kEnableGrallocUsageProtected) {        usage |= GRALLOC_USAGE_PROTECTED;    }    // Make sure to check whether either Stagefright or the video decoder    // requested protected buffers.    if (usage & GRALLOC_USAGE_PROTECTED) {        // Verify that the ANativeWindow sends images directly to        // SurfaceFlinger.        int queuesToNativeWindow = 0;        err = mNativeWindow->query(                mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,                &queuesToNativeWindow);        if (err != 0) {            ALOGE("error authenticating native window: %d", err);            return err;        }        if (queuesToNativeWindow != 1) {            ALOGE("native window could not be authenticated");            return PERMISSION_DENIED;        }    }    ALOGV("native_window_set_usage usage=0x%lx", usage);    /* all commons */    usage |= (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);    ALOGV("native_window_set_usage usage=0x%lx", usage);    err = native_window_set_usage(            mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);    if (err != 0) {        ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);        return err;    }    int minUndequeuedBufs = 0;    err = mNativeWindow->query(mNativeWindow.get(),            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);    if (err != 0) {        ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",                strerror(-err), -err);        return err;    }    // XXX: Is this the right logic to use?  It's not clear to me what the OMX    // buffer counts refer to - how do they account for the renderer holding on    // to buffers?    if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {        OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;        def.nBufferCountActual = newBufferCount;        err = mOMX->setParameter(                mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));        if (err != OK) {            CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",                    newBufferCount, err);            return err;        }    }    err = native_window_set_buffer_count(            mNativeWindow.get(), def.nBufferCountActual);    if (err != 0) {        ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err),                -err);        return err;    }    CODEC_LOGV("allocating %lu buffers from a native window of size %lu on "            "output port", def.nBufferCountActual, def.nBufferSize);    // Dequeue buffers and send them to OMX    for (OMX_U32 i = 0; i < def.nBufferCountActual; i++) {        ANativeWindowBuffer* buf;        err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf);        if (err != 0) {            ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err);            break;        }        sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false));        BufferInfo info;        info.mData = NULL;        info.mSize = def.nBufferSize;        info.mStatus = OWNED_BY_US;        info.mMem = NULL;        info.mMediaBuffer = new MediaBuffer(graphicBuffer);        info.mMediaBuffer->setObserver(this);        mPortBuffers[kPortIndexOutput].push(info);        IOMX::buffer_id bufferId;        err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer,                &bufferId);        if (err != 0) {            CODEC_LOGE("registering GraphicBuffer with OMX IL component "                    "failed: %d", err);            break;        }        mPortBuffers[kPortIndexOutput].editItemAt(i).mBuffer = bufferId;        CODEC_LOGV("registered graphic buffer with ID %p (pointer = %p)",                bufferId, graphicBuffer.get());    }    OMX_U32 cancelStart;    OMX_U32 cancelEnd;    if (err != 0) {        // If an error occurred while dequeuing we need to cancel any buffers        // that were dequeued.        cancelStart = 0;        cancelEnd = mPortBuffers[kPortIndexOutput].size();    } else {        // Return the last two buffers to the native window.        cancelStart = def.nBufferCountActual - minUndequeuedBufs;        cancelEnd = def.nBufferCountActual;    }    for (OMX_U32 i = cancelStart; i < cancelEnd; i++) {        BufferInfo *info = &mPortBuffers[kPortIndexOutput].editItemAt(i);        cancelBufferToNativeWindow(info);    }    return err;}

start的准备也做完了,主要是给port分配内存,基本也只是摘抄代码了

start以后,就要kick off了,下篇开始播放了

0 0