📄 htrencwrapper.cpp
字号:
{
LONG frameRateNum = pSettings->frameRate;
LONG frameRateDenom = 1;
// adjust H.263 framerate
if( pSettings->videoType == VIDEOTYPE_H263 )
{
frameRateNum *= 1000;
frameRateDenom *= 1001;
}
LONG numberOfMBs = pSettings->frameWidth/16 * pSettings->frameHeight/16;
LONG bitsPerFrame = pSettings->bitrate / frameRateNum * frameRateDenom;
LONG bitsPerMB = bitsPerFrame / numberOfMBs;
LONG QP;
if ( bitsPerMB < 20 ) QP = 30;
else if( bitsPerMB < 30 ) QP = 25;
else if( bitsPerMB < 40 ) QP = 20;
else if( bitsPerMB < 60 ) QP = 15;
else QP = 10;
return QP;
}
CHantroEncoderWrapper::CHantroEncoderWrapper()
: m_encInst(NULL)
, m_frameRateNum(0)
, m_frameRateDenom(0)
, m_uOffset(0)
, m_vOffset(0)
, m_intraRate(0)
, m_vopNumber(0)
, m_timestamp(0)
{
}
CHantroEncoderWrapper::~CHantroEncoderWrapper()
{
if( m_encInst != NULL )
{
MP4EncRelease( m_encInst );
m_encInst = NULL;
}
}
HRESULT CHantroEncoderWrapper::Init( Settings* pSettings )
{
// 1. Check for already running encoder
if( m_encInst != NULL )
{
return E_FAIL;
}
// 2. Validate settings parameters
HRESULT hr = ValidateSettings( pSettings );
if( FAILED(hr) )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED, invalid encoder settings parameters!\n" );
return hr;
}
// 3. Derive profile and level from settings
MP4EncProfileAndLevel profileAndLevel;
hr = GetProfileAndLevel( pSettings, &profileAndLevel, NULL );
if( FAILED(hr) )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED, invalid deriving profile and level settings!\n" );
return hr;
}
// 4. Init encoder
MP4EncCfg encCnfg;
encCnfg.profileAndLevel = profileAndLevel;
encCnfg.strmType = pSettings->videoType==VIDEOTYPE_MPEG4 ? MPEG4_PLAIN_STRM : H263_STRM;
encCnfg.width = pSettings->frameWidth;
encCnfg.height = pSettings->frameHeight;
encCnfg.frmRateNum = pSettings->frameRate;
encCnfg.frmRateDenom = 1;
// adjust H.263 framerate
if( pSettings->videoType == VIDEOTYPE_H263 )
{
encCnfg.frmRateNum *= 1000;
encCnfg.frmRateDenom *= 1001;
}
MP4EncInst encInst;
MP4EncRet encRetVal = MP4EncInit( &encCnfg, &encInst );
if( encInst == NULL )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED creating mp4enc instance (encRetVal=%d, encInst==NULL)!\n", (int)encRetVal );
return E_FAIL;
}
if( encRetVal != ENC_OK )
{
MP4EncRelease( encInst );
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED creating mp4enc instance (encRetVal=%d, encInst!=NULL)!\n", (int)encRetVal );
return E_FAIL;
}
// 5. Configure rate control
int QP = CalculateQP( pSettings );
MP4EncRateCtrl rateCtrl;
encRetVal = MP4EncGetRateCtrl( encInst, &rateCtrl );
if( encRetVal != ENC_OK )
{
MP4EncRelease( encInst );
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED getting rate control configuration (encRetVal=%d)!\n", (int)encRetVal );
return E_FAIL;
}
rateCtrl.vopRc = 1; // Enable adjustment of QP between VOPs
rateCtrl.mbRc = 1; // Enable macroblock based rate control
rateCtrl.vopSkip = 0; // Enable VOP skipping
rateCtrl.qpHdr = QP; // Set QP-parameters
rateCtrl.qpHdrMin = 1;
rateCtrl.qpHdrMax = 31;
rateCtrl.bitPerSecond = pSettings->bitrate; // Set the bitrate
rateCtrl.vbv = 1; // Enable/Disable video buffer verifier/
rateCtrl.cir = 0; // Let cyclic intra refresh rate to be what it has been initialized to/
encRetVal = MP4EncSetRateCtrl( encInst, &rateCtrl );
if( encRetVal != ENC_OK )
{
MP4EncRelease( encInst );
HTRENCW_DEBUG( "CHantroEncoderWrapper::Init: FAILED setting rate control configuration (encRetVal=%d)!\n", (int)encRetVal );
return E_FAIL;
}
m_encInst = encInst;
m_frameRateNum = pSettings->frameRate;
m_frameRateDenom = 1;
m_uOffset = pSettings->frameWidth*pSettings->frameHeight;
m_vOffset = pSettings->frameWidth*pSettings->frameHeight*5/4;
m_intraRate = pSettings->intraRefreshRate;
m_vopNumber = 0;
// adjust H.263 framerate
if( pSettings->videoType == VIDEOTYPE_H263 )
{
m_frameRateNum *= 1000;
m_frameRateDenom *= 1001;
}
HTRENCW_DEBUG_EXTRA( "CHantroEncoderWrapper::Init OK!\n" );
return S_OK;
}
HRESULT CHantroEncoderWrapper::Encode( DWORD busInputImage, REFERENCE_TIME* pStartTimestamp, REFERENCE_TIME* pEndTimestamp,
BYTE* pOutputStream, DWORD busOutputStream, LONG* pOutputStreamSize, BOOL* pKeyframe )
{
MP4EncIn encInput;
MP4EncOut encOutput;
MP4EncRet encRetVal;
// Setup encoder input
encInput.busLuma = busInputImage;
encInput.busChromaU = busInputImage + m_uOffset;
encInput.busChromaV = busInputImage + m_vOffset;
encInput.pOutBuf = (u32*)pOutputStream;
encInput.outBufBusAddress = busOutputStream;
encInput.outBufSize = *pOutputStreamSize;
encInput.pVpSizes = NULL;
encInput.vopType = m_intraRate && (m_vopNumber%m_intraRate==0) || m_vopNumber == 0 ?
INTRA_VOP : PREDICTED_VOP;
// timeIncrement = elapsed[100ns] * timescale [ticks/s] / 1[100ns/s]
encInput.timeIncr = (i32)( (*pStartTimestamp-m_timestamp)
* (REFERENCE_TIME)m_frameRateNum/(REFERENCE_TIME)m_frameRateDenom
/ (REFERENCE_TIME)10000000 );
// skip frame if input frame rate is higher than target, trigered when
// the computed timeIncrement is negative and two frames behind
if( encInput.timeIncr < 0 )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::Encode WARNING: skiping frame, input framerate is higher than target, vopNumber=%d, inputTs=%d, encoderTs=%d\n", m_vopNumber, (int)*pStartTimestamp, (int)m_timestamp );
*pOutputStreamSize = 0;
*pKeyframe = 0;
return S_FALSE;
}
// adjust timeIncrement to start on 0 and multiple of frameRateDenom
if( encInput.timeIncr<1 && m_vopNumber>0 ) encInput.timeIncr = 1;
encInput.timeIncr *= m_frameRateDenom;
// update [internally kept] timestamp to match actual timestamp passed to encoder
m_timestamp += encInput.timeIncr
* (REFERENCE_TIME)10000000
/ (REFERENCE_TIME)m_frameRateNum;
// update user provided start timestamp
*pStartTimestamp = m_timestamp;
// update user provided end timestamp
i32 duration = (i32)( (*pEndTimestamp-m_timestamp)
* (REFERENCE_TIME)m_frameRateNum
/ (REFERENCE_TIME)10000000 );
if( duration < 0 ) duration = 0;
*pEndTimestamp = m_timestamp + duration
* (REFERENCE_TIME)10000000
/ (REFERENCE_TIME)m_frameRateNum;
// Actual encoding!
encRetVal = MP4EncStrmEncode( m_encInst, &encInput, &encOutput );
switch (encRetVal)
{
case ENC_VOP_READY_VBV_FAIL: // the frame is ready but the VBV model noticed an overflow. Too few bits are generated. Frame rate may be too low.
HTRENCW_DEBUG( "CHantroEncoderWrapper::Encode WARNING, VOP ready, VBV failed\n" );
case ENC_VOP_READY: // a frame encoding was finished
case ENC_GOV_READY: //the GOV header was generated. Call again to continue with the frame encoding.
*pOutputStreamSize = encOutput.strmSize;
*pKeyframe = encOutput.vopType == INTRA_VOP;
m_vopNumber++;
return S_OK;
case ENC_OUTPUT_BUFFER_OVERFLOW: // error, the output buffer抯 size was too small to fit the generated stream. The whole frame is lost. New frame encoding has to be started.
case ENC_HW_TIMEOUT: // error, the wait for a hardware finish has timed out. The current frame is lost. New frame encoding has to be started.
case ENC_SYSTEM_ERROR: // error, a system error was caught. The current frame is lost. New frame encoding has to be started.
case ENC_INVALID_ARGUMENT: // error, one of the arguments was invalid
HTRENCW_DEBUG( "CHantroEncoderWrapper::Encode WARNING, non-critical encoding error %d\n", (int)encRetVal );
*pOutputStreamSize = 0;
*pKeyframe = 0;
return S_FALSE;
case ENC_NULL_ARGUMENT: // error, a pointer argument had an invalid NULL value
case ENC_HW_ERROR: // error, a hardware error was caught. This can be caused by invalid bus addresses, addresses
case ENC_INSTANCE_ERROR: // error, an invalid encoder instance was specified
case ENC_INVALID_STATUS: // error, a stream was not started yet
default:
HTRENCW_DEBUG( "CHantroEncoderWrapper::Encode FAILED encoding error %d\n", (int)encRetVal );
*pOutputStreamSize = 0;
*pKeyframe = 0;
return E_FAIL;
}
// shouldn't get here
return E_FAIL;
}
HRESULT CHantroEncoderWrapper::StartStream( BYTE* pOutputStream, LONG* pOutputStreamSize )
{
MP4EncIn encInput;
MP4EncOut encOutput;
MP4EncRet encRetVal;
encInput.pOutBuf = (u32*)pOutputStream;
encInput.outBufSize = *pOutputStreamSize;
encRetVal = MP4EncStrmStart( m_encInst, &encInput, &encOutput );
if( encRetVal != ENC_OK )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::StartStream: FAILED (encRetVal=%d)!\n", (int)encRetVal );
return E_FAIL;
}
*pOutputStreamSize = encOutput.strmSize;
HTRENCW_DEBUG_EXTRA( "CHantroEncoderWrapper::StartStream OK!\n" );
return S_OK;
}
HRESULT CHantroEncoderWrapper::EndStream( BYTE* pOutputStream, LONG* pOutputStreamSize )
{
MP4EncIn encInput;
MP4EncOut encOutput;
MP4EncRet encRetVal;
encInput.pOutBuf = (u32*)pOutputStream;
encInput.outBufSize = *pOutputStreamSize;
encRetVal = MP4EncStrmEnd( m_encInst, &encInput, &encOutput );
if( encRetVal != ENC_OK )
{
HTRENCW_DEBUG( "CHantroEncoderWrapper::EndStream FAILED (encRetVal=%d)!\n", (int)encRetVal );
return E_FAIL;
}
*pOutputStreamSize = encOutput.strmSize;
HTRENCW_DEBUG_EXTRA( "CHantroEncoderWrapper::EndStream OK!\n" );
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -