在《Android視頻編碼源碼分享》一文中,我們主要學(xué)習(xí)的是Android視頻編碼的實(shí)現(xiàn)方法,本文要給大家講述的則是Android中視頻的解碼過程。
在Android中,解碼器的具體實(shí)現(xiàn)會(huì)被封裝在一個(gè)OpenMAX組件中,對(duì)于視頻的編碼器,相應(yīng)的組件為OpenmaxMpeg4AO,該組件被Mpeg4OmxComponentFactory、H263OmxComponentFactory等組件工廠共有,用來實(shí)現(xiàn)對(duì)H.263和MPEG-4的解碼。提供給記錄引擎的接口為OpenmaxMpeg4AO::ProcessData()方法,實(shí)際的解碼工作在 Mpeg4 Decoder_OMX::Mp4DecodeVideo ()方法中實(shí)現(xiàn)。下面是該方法的具體實(shí)現(xiàn):
代碼:視頻的解碼過程
MX_BOOL Mpeg4Decoder_OMX::Mp4DecodeVideo(OMX_BUFFERHEADERTYPE* aOutBuffer, OMX_U32*
aOutputLength,OMX_U8** aInputBuf, OMX_U32* aInBufSize,
OMX_PARAM_PORTDEFINITIONTYPE* aPortParam, OMX_BOOL aDeBlocking,
OMX_S32* aFrameCount, OMX_BOOL aMarkerFlag, OMX_BOOL *aResizeFlag)
{
OMX_BOOL Status=OMX_TRUE;
OMX_S32 OldWidth, OldHeight;
OldWidth=aPortParam->format.video.nFrameWidth;
OldHeight=aPortParam->format.video.nFrameHeight;
*aResizeFlag=OMX_FALSE;
#ifdef _DEBUG
static OMX_U32 FrameCount=0;
#endif
uint UseExtTimestamp=0;
uint32 TimeStamp;
OMX_S32 InputSize, InitSize;
if ((Mpeg4InitCompleteFlag==OMX_FALSE) && (MPEG4_MODE==CodecMode))
{
if (!aMarkerFlag)
{
InitSize=GetVideoHeader(0, *aInputBuf, *aInBufSize);
}
else
{
InitSize=*aInBufSize;
}
//初始化解碼
if (PV_TRUE!=InitializeVideoDecode(&iDisplay_Width, &iDisplay_Height,aInputBuf, (OMX_S32*)aInBufSize, MPEG4_MODE, aDeBlocking))
return OMX_FALSE;
Mpeg4InitCompleteFlag=OMX_TRUE;
aPortParam->format.video.nFrameWidth=iDisplay_Width;
aPortParam->format.video.nFrameHeight=iDisplay_Height;
OMX_U32 min_stride=((aPortParam->format.video.nFrameWidth+15) & (~15));
OMX_U32 min_sliceheight=((aPortParam->format.video.nFrameHeight+15) & (~15));
aPortParam->format.video.nStride=min_stride;
aPortParam->format.video.nSliceHeight=min_sliceheight;
//解碼器組件總是輸出YUV420格式
aPortParam->nBufferSize=(aPortParam->format.video.nSliceHeight*aPortParam->
format.video.nStride * 3)>>1;
iFrameSize=(aPortParam->format.video.nSliceHeight * aPortParam->format. video.nStride);
if ((iDisplay_Width !=OldWidth) || (iDisplay_Height !=OldHeight))
{
*aResizeFlag=OMX_TRUE;
}
else if (NULL !=aOutBuffer)
{
PVSetReferenceYUV(&VideoCtrl, (uint8*)(aOutBuffer->pBuffer));
BufferCtrlStruct *pBCTRL=(BufferCtrlStruct *)(aOutBuffer-> pOutputPortPrivate);
pBCTRL->iRefCount++;
ipRefCtrPreviousReferenceBuffer=&(pBCTRL->iRefCount);
iReferenceYUVWasSet=OMX_TRUE;
}
*aFrameCount=1;
*aInBufSize -=InitSize;
return OMX_TRUE;
}
if ((*(OMX_S32*)aInBufSize) <=0)
{
return OMX_FALSE;
}
TimeStamp=0xFFFFFFFF;
InputSize=*aInBufSize;
if ((OMX_FALSE==Mpeg4InitCompleteFlag) && (H263_MODE==CodecMode))
{
int32 aligned_width, aligned_height;
int32 display_width, display_height;
//獲取配置信息
if (iGetM4VConfigInfo(*aInputBuf, *aInBufSize, &aligned_width, &aligned_height,&display_width, &display_height))
{
return OMX_FALSE;
}
Mpeg4InitCompleteFlag=OMX_TRUE;
iDisplay_Width=display_width;
iDisplay_Height=display_height;
aPortParam->format.video.nFrameWidth=iDisplay_Width; // use non 16byte aligned values (display_width) for H263
aPortParam->format.video.nFrameHeight=iDisplay_Height; // like in the case of M4V (PVGetVideoDimensions also returns display_width/height)
OMX_U32 min_stride=((aPortParam->format.video.nFrameWidth+15) & (~15));
OMX_U32 min_sliceheight=((aPortParam->format.video.nFrameHeight+15) & (~15));
aPortParam->format.video.nStride=min_stride;
aPortParam->format.video.nSliceHeight=min_sliceheight;
aPortParam->nBufferSize=(aPortParam->format.video.nSliceHeight * aPortParam->format.video.nStride * 3) >> 1;
iFrameSize=(aPortParam->format.video.nSliceHeight * aPortParam->format.video.nStride);
if ((iDisplay_Width !=OldWidth)||(iDisplay_Height !=OldHeight))
{
*aResizeFlag=OMX_TRUE;
}
else if (NULL !=aOutBuffer)
{
PVSetReferenceYUV(&VideoCtrl, (uint8*)(aOutBuffer->pBuffer));
BufferCtrlStruct *pBCTRL=(BufferCtrlStruct *)(aOutBuffer->pOutputPortPrivate);
pBCTRL->iRefCount++;
ipRefCtrPreviousReferenceBuffer=&(pBCTRL->iRefCount);
iReferenceYUVWasSet=OMX_TRUE;
}
*aFrameCount=1;
return OMX_TRUE;
}
if (iReferenceYUVWasSet==OMX_FALSE)
{
PVSetReferenceYUV(&VideoCtrl, (uint8*)(aOutBuffer->pBuffer));
BufferCtrlStruct *pBCTRL=(BufferCtrlStruct *)(aOutBuffer-> pOutputPortPrivate);
pBCTRL->iRefCount++;
ipRefCtrPreviousReferenceBuffer=&(pBCTRL->iRefCount);
iReferenceYUVWasSet=OMX_TRUE;
return OMX_TRUE;
}
#if PROFILING_ON
OMX_U32 StartTime=OsclTickCount::TickCount();
#endif
//針對(duì)一幀進(jìn)行解碼
Status=(OMX_BOOL) PVDecodeVideoFrame(&VideoCtrl, aInputBuf,&TimeStamp,(int32*)aInBufSize,&UseExtTimestamp,(OMX_U8*)(aOutBuffer->pBuffer));
#if PROFILING_ON
OMX_U32 EndTime=OsclTickCount::TickCount();
iTotalTicks +=(EndTime-StartTime);
#endif
if (Status==PV_TRUE)
{
#ifdef _DEBUG
#endif
*aInputBuf +=(InputSize-*aInBufSize);
(*ipRefCtrPreviousReferenceBuffer)--;
if ((*ipRefCtrPreviousReferenceBuffer)==0)
{
ipOMXComponent->iNumAvailableOutputBuffers++;
}
BufferCtrlStruct *pBCTRL=(BufferCtrlStruct *)(aOutBuffer-> pOutputPortPrivate);
pBCTRL->iRefCount++;
ipRefCtrPreviousReferenceBuffer=&(pBCTRL->iRefCount);
*aOutputLength=(iFrameSize * 3)>>1;
(*aFrameCount)++;
}
else
{
*aInBufSize=InputSize;
*aOutputLength=0;
}
return Status;
}
在進(jìn)行解碼時(shí),會(huì)首先判斷編碼格式是MPEG4_MODE還是H263_MODE,如果是MPEG4_MODE,則首先通過GetVideoHeader()方法讀取視頻的頭信息,然后通過InitializeVideoDecode()方法初始化視頻解碼器,終將數(shù)據(jù)解碼為YUV420格式的元數(shù)據(jù)。如果編碼格式為H263_MODE,則首先通過iGetM4VConfigInfo()方法獲取M4V文件的配置信息,終將數(shù)據(jù)解碼為YUV420格式的元數(shù)據(jù)。