⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htrencwrapper.cpp

📁 freescale i.mx31 BSP CE5.0全部源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
{
    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 + -