在Android中,編碼器的具體實(shí)現(xiàn)會(huì)被封裝在一個(gè)OpenMAX組件中,對(duì)于MP4的編碼器,相應(yīng)的組件為OmxComponentMpeg4EncAO,該組件被Mpeg4EncOmxComponentFactory、H263EncOmxComponentFactory等組件工廠共有,用來實(shí)現(xiàn)對(duì)H.263和MPEG-4的編碼。提供給記錄引擎的接口為OmxComponentMpeg4EncAO::ProcessData()方法,實(shí)際的編碼工作在 Mpeg4Encoder_OMX::Mp4EncodeVideo()中實(shí)現(xiàn)。下面是該方法的具體實(shí)現(xiàn):
代碼:視頻的編碼過程
OMX_BOOL Mpeg4Encoder_OMX::Mp4EncodeVideo(OMX_U8* aOutBuffer,
OMX_U32* aOutputLength, //輸出長度
OMX_BOOL* aBufferOverRun, //運(yùn)行緩沖
OMX_U8** aOverBufferPointer,
OMX_U8* aInBuffer, //輸入緩沖
OMX_U32 aInBufSize,
OMX_TICKS aInTimeStamp,
OMX_TICKS* aOutTimeStamp,
OMX_BOOL* aSyncFlag) // OMX_FALSE或者OMX_TRUE
{
*aSyncFlag=OMX_FALSE;
if (OMX_FALSE==iModTimeInitialized)
{
iNextModTime=aInTimeStamp;
iModTimeInitialized=OMX_TRUE;
}
if (OMX_COLOR_FormatYUV420Planar==iVideoFormat) //YUV420元數(shù)據(jù)
{
if (aInBufSize<(OMX_U32)((iSrcWidth * iSrcHeight * 3) >> 1))
{
*aOutputLength=0;
return OMX_FALSE;
}
}
else if (OMX_COLOR_Format24bitRGB888==iVideoFormat) //RGB888元數(shù)據(jù)
{
if (aInBufSize<(OMX_U32)(iSrcWidth * iSrcHeight * 3))
{
*aOutputLength=0;
return OMX_FALSE;
}
}
else if (OMX_COLOR_Format12bitRGB444==iVideoFormat) //RGB444元數(shù)據(jù)
{
if (aInBufSize<(OMX_U32)(iSrcWidth * iSrcHeight * 2))
{
*aOutputLength=0;
return OMX_FALSE;
}
}
else if (OMX_COLOR_FormatYUV420SemiPlanar==iVideoFormat) //YUV420元數(shù)據(jù)
{
if (aInBufSize<(OMX_U32)((iSrcWidth * iSrcHeight * 3)>>1))
{
*aOutputLength=0;
return OMX_FALSE;
}
}
else if ((OMX_COLOR_FormatYCbYCr==iVideoFormat) ||
(OMX_COLOR_FormatYCrYCb==iVideoFormat) ||
(OMX_COLOR_FormatCbYCrY==iVideoFormat) ||
(OMX_COLOR_FormatCrYCbY==iVideoFormat))
{
if (aInBufSize<(OMX_U32)(iSrcWidth * iSrcHeight * 2))
{
*aOutputLength=0;
return OMX_FALSE;
}
}
//開始對(duì)輸入緩沖解碼
VideoEncFrameIO vid_in, vid_out;
Int Size;
Bool status;
ULong modTime;
Int nLayer=0;
if ((iNextModTime * 1000) <=aInTimeStamp)
{
Size=*aOutputLength;
#if PROFILING_ON
OMX_U32 Start=OsclTickCount::TickCount();
#endif
if (iVideoFormat==OMX_COLOR_FormatYUV420Planar)
{
if (iYUVIn)
{//對(duì)YUV元數(shù)據(jù)進(jìn)行復(fù)制
CopyToYUVIn(aInBuffer, iSrcWidth, iSrcHeight,
((iSrcWidth+15)>>4)<<4, ((iSrcHeight+15)>>4)<<4);
iVideoIn=iYUVIn;
}
else
{
iVideoIn=aInBuffer;
}
}
else if ((iVideoFormat==OMX_COLOR_Format12bitRGB444) ||
(iVideoFormat==OMX_COLOR_Format24bitRGB888) ||
(iVideoFormat==OMX_COLOR_FormatYUV420SemiPlanar) ||
(iVideoFormat==OMX_COLOR_FormatYCbYCr) ||
(iVideoFormat==OMX_COLOR_FormatYCrYCb) ||
(iVideoFormat==OMX_COLOR_FormatCbYCrY) ||
(iVideoFormat==OMX_COLOR_FormatCrYCbY))
{/ /元數(shù)據(jù)格式轉(zhuǎn)換
ccRGBtoYUV->Convert((uint8*)aInBuffer, iYUVIn);
iVideoIn=iYUVIn;
}
#if PROFILING_ON
OMX_U32 Stop=OsclTickCount::TickCount();
iProfileStats.iColorConversionTime +=(Stop-Start);
++iProfileStats.iTotalNumFrames;
OMX_U32 StartTime=OsclTickCount::TickCount();
#endif
*aOutTimeStamp=aInTimeStamp;
vid_in.height=((iSrcHeight+15)>>4)<<4;
vid_in.pitch=((iSrcWidth+15)>>4)<<4;
vid_in.timestamp=(ULong)(aInTimeStamp / 1000);
vid_in.yChan=(UChar*)iVideoIn;
vid_in.uChan=(UChar*)(iVideoIn+vid_in.height * vid_in.pitch);
vid_in.vChan=vid_in.uChan+((vid_in.height * vid_in.pitch) >> 2);
//進(jìn)行一幀YUV數(shù)據(jù)的編碼
status=PVEncodeVideoFrame(&iEncoderControl, &vid_in, &vid_out,&modTime, (UChar*)aOutBuffer,&Size, &nLayer);
#if PROFILING_ON
OMX_U32 EndTime=OsclTickCount::TickCount();
iProfileStats.iTotalEncTime +=(EndTime-StartTime);
if ((PV_TRUE==status) && (Size > 0))
{
++iProfileStats.iNumFramesEncoded;
iProfileStats.iDuration=vid_out.timestamp;
}
#endif
if (status==PV_TRUE)
{
iNextModTime=modTime; //以毫秒為單位
if ((nLayer >=0) && ((OMX_U32) Size > *aOutputLength))
{
*aOverBufferPointer=PVGetOverrunBuffer(&iEncoderControl);
*aBufferOverRun=OMX_TRUE;
}
*aOutputLength=Size;
if (Size > 0)
{
//轉(zhuǎn)換毫秒為微秒
*aOutTimeStamp=((OMX_TICKS) vid_out.timestamp * 1000);
PVGetHintTrack(&iEncoderControl, &iHintTrack);
if (0==iHintTrack.CodeType)
{
*aSyncFlag=OMX_TRUE;
}
}
return OMX_TRUE;
}
else
{
*aOutputLength=0;
return OMX_FALSE;
}
}
else
{
*aOutputLength=0;
return OMX_TRUE;
}
}
從編碼過程可以看出,在進(jìn)行編碼時(shí),首先要判斷出元數(shù)據(jù)的格式,如果不是OMX_COLOR_FormatYUV420Planar格式,則調(diào)用ColorConvertBase:: Convert()方法對(duì)元數(shù)據(jù)格式進(jìn)行轉(zhuǎn)換,然后通過PVEncodeVideoFrame()方法針對(duì)當(dāng)前一幀進(jìn)行編碼。
對(duì)于MPEG-4,向組件庫注冊(cè)的注冊(cè)函數(shù)為Mpeg4EncRegister(),組件名為“OMX.PV. mpeg4enc”;對(duì)于H263,向組件庫注冊(cè)的注冊(cè)函數(shù)為H263EncRegister(),組件名為“OMX.PV.h263enc”。
Mpeg4Encoder_OMX的編碼模式為MODE_H263和MODE_MPEG4。