函数OpenmaxMp3AO::ProcessData()是omx中MP3格式的数据处理函数,也就是进行解码的函数,它会调用到类Mp3Decoder中的Mp3DecodeAudio函数来实现解码。函数Mp3DecodeAudio的实现就是调用体层的解码库实现了。也就是软解码库的对外接口。
函数流程:
1)分别从输入端口(port)和输出端口中读取pBufferQueue(buffer队列),并保存为pInputQueue和pOutputQueue,两者类型是QueueType*,关于此类型前面讲过;
2)保存输入输出端口;
3)获取&iOmxComponent,用pHandle保存,其类型是OMX_COMPONENTTYPE*(是OpenMax的标准类型);
(上面三步都是参数的传递,算是数据处理前的准备工作)
4)定义了几个变量;在数据处理时会用到。其中有个变量TempInputBufferSize,其定义如下:
OMX_U32 TempInputBufferSize = (2 * sizeof(uint8) * (ipPorts[OMX_PORT_INPUTPORT_INDEX]->PortParam.nBufferSize));数值为36864
看其字面意思是临时输入buffer的大小,可能是在数据处理时并不是直接对传过来的Inputbuffer进行处理,而是先将Inputbuffer传给一个临时的buffer,对临时的buffer进行处理。
5)判断参数iIsInputBufferEnded(用于判断传递输入buffer是否结束?)和iEndofStream(数据流结束标志)这两个参数但是基础组件类的成员量。在构建OmxComponentBase的时候,两者初始化为:
iIsInputBufferEnded = OMX_TRUE;
iEndofStream = OMX_FALSE;
满足条件((!iIsInputBufferEnded) || iEndofStream)才有可能进入解码函数。不满足条件,直接退出函数。
6)判断参数iSilenceInsertionInProgress,为真会调用函数DoSilenceInsertion();(函数作用?在整个MP3解码中没有调用到?)
7)判断参数iNewOutBufRequired是否需要新的输出buffer,如果为真,进入8),
如为假,进入14);
8)首先调用函数GetQueueNumElem检查输出buffer队列是否有可用的输出buffer,GetQueueNumElem(QueueType* aQueue)返回aQueue中的当前元素个数。
若有,进入9);
9)调用函数DeQueue,函数DeQueue(QueueType* aQueue),返回aQueue->pFirst->pData,类型转换为
OMX_BUFFERHEADERTYPE*,保存到ipOutputBuffer,就是获取一个指向输出buffer的指针,并将此输出buffer的参数nFilledLen值初始化为0,还有就是时间戳的设置。
10)判断参数iSendOutBufferAfterPortReconfigFlag,若为假,进入14);
{通常第一次进入解码过程时为假,因为这个变量标志着是否在临时输出buffer(ipTempOutBufferForPortReconfig)中存有已经解码过的数据,其实输出buffer的数据传递模式与输入buffer类似,同样是解码函数后先将解码过得数据存到临时输出buffer中,再在下次进入此函数时将临时输出buffer的数据传递给ipOutputBuffer->pBuffer,这样一次次的积累,指导填满,才会将输出buffer中,不过每次的ipOutputBuffer是不一样的啊}
对ipOutputBuffer重新配置,如果指针ipTempOutBufferForPortReconfig指向内容不为空,而且内容长度不会超出输出buffer分配的空间大小,则调用oscl_memcpy(ipOutputBuffer->pBuffer, ipTempOutBufferForPortReconfig, iSizeOutBufferForPortReconfig)
将ipTempOutBufferForPortReconfig(??,存什么数据?)拷贝长度为iSizeOutBufferForPortReconfig的内容到ipOutputBuffer->pBuffer;同时更新输出buffer中的字节数(nFilledLen),设置ipOutputBuffer->nFilledLen(buffer中元素数,也就是已使用的字节数) = iSizeOutBufferForPortReconfig,并设置iSendOutBufferAfterPortReconfigFlag为假。
12)(ipOutputBuffer->nAllocLen - ipOutputBuffer->nFilledLen) < iOutputFrameLength,判断在ipOutputBuffer中剩余的字节数是否能满足输出frame的要求,前者小说明输出buffer已满,则调用函数ReturnOutputBuffer(ipOutputBuffer, pOutPort)(貌似是将输出buffer返回到输出端口),接着free掉ipTempOutBufferForPortReconfig(这个仅是起一个传递作用,过河拆桥);
13)检查参数iNewOutBufRequired,因为前面可能会调用到函数ReturnOutputBuffer()将剩余空间不足的buffer返回到输出端口了,所以要重新判断,如果仍需要新的buffer,则继续将outbuffer出列使用;
14)将ipOutputBuffer中的剩余的buffer保存到pOutBuffer中;并计算了一个值就是OutputLength,是输出buffer中剩余空间的一半;这两个参数都会作为解码函数的参数;
15)检查临时输入buffer(ipTempInputBuffer)中有没有数据,以及临时输入buffer(iTempInputBufferLength)的数据长度和当前输入buffer(iInputCurrLength)的数据长度的和是否小于前面分配的TempInputBufferSize,满足条件则将临时输入buffer中的数据也复制到ipFrameDecodeBuffer;
变量ipFrameDecodeBuffer是基础组件类的成员变量,其类型是OMX_U8*,从类型也可以看出同buffer(ipOutputBuffer和ipInputBuffer)中的pBuffer是同一类型,其实这个变量的作用就是保存输入buffer的pBuffer,作为解码函数的参数;
判断参数iTempInputBufferLength是否大于0以及TempInputBufferSize(本函数前面分配的)是否满足(iInputCurrLength + iTempInputBufferLength) < TempInputBufferSize若满足条件,则将ipFrameDecodeBuffer拷贝到ipTempInputBuffer中
16)调用函数Mp3Decoder::Mp3DecodeAudio,进入解码流程;
17)ResizeNeeded(上面解码函数的一个参数)为假,跳到19);
ResizeNeeded标志是否要重新配置每帧的采样数(iSamplesPerFrame),是对输出端口的AudioPcmMode中的nSamplingRate进行配置;
18)为ipTempOutBufferForPortReconfig分配了一段空间,将pOutBuffer的内容复制到其中,复制长度是OutputLength * 2;调用回调函数;
19)更新输出buffer的nFilledLen,加上OutputLength * 2;
20)DecodeReturn(解码函数的返回值)如果为成功,更新输入buffer的nFilledLen,设置为iInputCurrLength,是当前输入buffer中的数据长度,也就是剩下的没有解码处理的数据,在解码函数中更新,所以两值相减可以计算出此次处理了多少数据;
21)如果返回MP3DEC_INCOMPLETE_FRAME,说明ipFrameDecodeBuffer的数据太少,不够一帧,复制到临时buffer中去,供下次解码使用;
22)返回其他的就是解码出错了;
23)判断ipInputBuffer->nFilledLen,如果为零说明输入buffer已经处理完了,调用函数ReturnInputBuffer(ipInputBuffer, pInPort),返回给输入端口;
24)判断输出buffer中的剩余空间是否能满足一个frame的大小要求,如果不满足,调用函数将输出buffer返回给输出端口;
25)结束