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
- OMXCodec源码分析---part2
- OMXCodec源码分析---part2
- OMXCodec源码分析---part1
- 《Volley源码分析》Part2、Volley源码解析
- Andoird OMXCodec 流程分析
- OMXCodec,
- 实现分析 - Enemy part2
- E/OMXCodec( 255): [OMX.google.amrnb.encoder]出错问题分析
- part2
- PART2
- (四)Spark源码理解之BlockManager---part2
- (六)Spark源码理解之RDD----part2
- (七)Spark源码理解之TaskScheduler----part2
- (八)Spark源码理解之DAGScheduler---part2
- Atitit.词法分析的理论原理 part2
- 蓝牙解析(part2):协议架构分析
- OMXCodec执行流程细节
- OMXCodec数据处理过程
- 第三章作业
- 使用beanUtils操作javabean
- Ubuntu桌面图标消失解决办法
- JDBC的一个实例
- tex 如何安装package?
- OMXCodec源码分析---part2
- C-数组地址(4)
- 网络营销计划该当留意什么
- 马云与四大行支付战争全篇解读
- 矩形类的构造函数
- svn Can't revert without reverting children 解决方案
- count(*)与count(id)
- 实现SMTP批量发信之LoadRunner与JMeter
- IOS7 下修改 UINavigationBar 的背景色和设置标题的颜色