硬件编解码(七)Intel提供的QuickSync使用样例(4)视频编码

来源:互联网 发布:移民澳洲 知乎 编辑:程序博客网 时间:2024/05/20 19:48

视频编码



编码的流程


流程如下:
    1、一些初始的相关设置
    2、进入第一个while循环
        (1)获取一个空闲的任务
        (2)获取输入缓存区
        (3)读取一个帧
        (4)如果有需要就调用RunFrameVPPAsync,对让视频预处理器(vpp)对视频进行处理,注意它是一个异步函数
        (5)调用EncodeFrameAsync对帧进行编码,注意它也是一个异步函数,这意味着该函数只是把输入帧放进编码器中而已,不等待它处理完成就返回了
    3、如果有必要,进入第二个while循环,这个循环目的是得到视频预处理器的输出,因为RunFrameVPPAsync是一个异步函数
    4、进入第三个while循环,这个循环的目的是得到编码器的输出,因为EncodeFrameAsync是一个异步函数



编码函数的实现


mfxStatus CEncodingPipeline::Run(){    m_statOverall.StartTimeMeasurement();    MSDK_CHECK_POINTER(m_pmfxENC, MFX_ERR_NOT_INITIALIZED);// 起始状态:无错误    mfxStatus sts = MFX_ERR_NONE;    mfxFrameSurface1* pSurf = NULL; // dispatching pointer    sTask *pCurrentTask = NULL; // a pointer to the current task    mfxU16 nEncSurfIdx = 0;     // index of free surface for encoder input (vpp output)    mfxU16 nVppSurfIdx = 0;     // index of free surface for vpp input    mfxSyncPoint VppSyncPoint = NULL; // a sync point associated with an asynchronous vpp call    bool bVppMultipleOutput = false;  // this flag is true if VPP produces more frames at output    // than consumes at input. E.g. framerate conversion 30 fps -> 60 fps    // Since in sample we support just 2 views    // we will change this value between 0 and 1 in case of MVC    mfxU16 currViewNum = 0;    mfxU32 nFramesProcessed = 0;    sts = MFX_ERR_NONE;#if defined (ENABLE_V4L2_SUPPORT)    if (isV4L2InputEnabled)    {        msdk_printf(MSDK_STRING("Press Ctrl+C to terminate this application\n"));    }#endif/*** 这个循环的目的是从文件中读取图像,把图像传给预处理器(如果有需要)处理,然后把** 处理过后的帧传给编码器,让编码器进行编码,注意,编码函数是一个异步函数,它不会等待编码的结果** 把图像传进去之后就立即返回了*/    // main loop, preprocessing and encoding    while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts)    {        if ((m_nFramesToProcess != 0) && (nFramesProcessed == m_nFramesToProcess))        {            break;        }#if defined (ENABLE_V4L2_SUPPORT)        if (v4l2Pipeline.GetV4L2TerminationSignal() && isV4L2InputEnabled)        {            break;        }#endif        // get a pointer to a free task (bit stream and sync point for encoder)// 获取一个空闲任务        sts = GetFreeTask(&pCurrentTask);        MSDK_BREAK_ON_ERROR(sts);        // find free surface for encoder input// 内存获取        if (m_nMemBuffer && !m_pmfxVPP)        {            nEncSurfIdx %= m_nMemBuffer;        }        else        {            nEncSurfIdx = GetFreeSurface(m_pEncSurfaces, m_EncResponse.NumFrameActual);        }        MSDK_CHECK_ERROR(nEncSurfIdx, MSDK_INVALID_SURF_IDX, MFX_ERR_MEMORY_ALLOC);        // point pSurf to encoder surface        pSurf = &m_pEncSurfaces[nEncSurfIdx];        if (!bVppMultipleOutput)        {            // if vpp is enabled find free surface for vpp input and point pSurf to vpp surface            if (m_pmfxVPP)            {#if defined (ENABLE_V4L2_SUPPORT)                if (isV4L2InputEnabled)                {                    nVppSurfIdx = v4l2Pipeline.GetOffQ();                }#else                if (m_nMemBuffer)                {                    nVppSurfIdx = nVppSurfIdx % m_nMemBuffer;                }                else                {                    nVppSurfIdx = GetFreeSurface(m_pVppSurfaces, m_VppResponse.NumFrameActual);                }                MSDK_CHECK_ERROR(nVppSurfIdx, MSDK_INVALID_SURF_IDX, MFX_ERR_MEMORY_ALLOC);#endif                pSurf = &m_pVppSurfaces[nVppSurfIdx];            }            pSurf->Info.FrameId.ViewId = currViewNum;            m_statFile.StartTimeMeasurement();// 读取一个帧            sts = LoadNextFrame(pSurf);            m_statFile.StopTimeMeasurement();            if ( (MFX_ERR_MORE_DATA == sts) && !m_bTimeOutExceed)                continue;            MSDK_BREAK_ON_ERROR(sts);            m_statFile.StopTimeMeasurement();            if (MVC_ENABLED & m_MVCflags) currViewNum ^= 1; // Flip between 0 and 1 for ViewId        }        // perform preprocessing if required// 如果需要预处理(vpp)        if (m_pmfxVPP)        {            bVppMultipleOutput = false; // reset the flag before a call to VPP            for (;;)            {// 视频预处理,注意它是一个异步函数,这表示着for循环结束也不一定能获取所有输出                sts = m_pmfxVPP->RunFrameVPPAsync(&m_pVppSurfaces[nVppSurfIdx], &m_pEncSurfaces[nEncSurfIdx],                    NULL, &VppSyncPoint);                if (m_nMemBuffer)                {                   // increment buffer index                   nVppSurfIdx++;                }                if (MFX_ERR_NONE < sts && !VppSyncPoint) // repeat the call if warning and no output                {                    if (MFX_WRN_DEVICE_BUSY == sts)                        MSDK_SLEEP(1); // wait if device is busy                }                else if (MFX_ERR_NONE < sts && VppSyncPoint)                {                    sts = MFX_ERR_NONE; // ignore warnings if output is available                    break;                }                else                    break; // not a warning            }            // process errors            if (MFX_ERR_MORE_DATA == sts)            {                continue;            }            else if (MFX_ERR_MORE_SURFACE == sts)            {                bVppMultipleOutput = true;            }            else            {                MSDK_BREAK_ON_ERROR(sts);            }        }        // save the id of preceding vpp task which will produce input data for the encode task        if (VppSyncPoint)        {            pCurrentTask->DependentVppTasks.push_back(VppSyncPoint);            VppSyncPoint = NULL;        }// 循环,把帧都放进编码器中,让编码器去处理// 注意循环结束之后,不表示可以得到所有输出,因为调用的是一个异步函数        for (;;)        {// 插入一个IDR帧,IDR帧是关键帧            InsertIDR(m_bInsertIDR);            // at this point surface for encoder contains either a frame from file or a frame processed by vpp            sts = m_pmfxENC->EncodeFrameAsync(&m_encCtrl, &m_pEncSurfaces[nEncSurfIdx], &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);            m_bInsertIDR = false;            if (m_nMemBuffer)            {                // increment buffer index                nEncSurfIdx++;            }            if (MFX_ERR_NONE < sts && !pCurrentTask->EncSyncP) // repeat the call if warning and no output            {                if (MFX_WRN_DEVICE_BUSY == sts)                    MSDK_SLEEP(1); // wait if device is busy            }            else if (MFX_ERR_NONE < sts && pCurrentTask->EncSyncP)            {                sts = MFX_ERR_NONE; // ignore warnings if output is available                break;            }            else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)            {                sts = AllocateSufficientBuffer(&pCurrentTask->mfxBS);                MSDK_CHECK_STATUS(sts, "AllocateSufficientBuffer failed");            }            else            {                // get next surface and new task for 2nd bitstream in ViewOutput mode                MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_BITSTREAM);                break;            }        }        nFramesProcessed++;    }    // means that the input file has ended, need to go to buffering loops    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);    // exit in case of other errors    MSDK_CHECK_STATUS(sts, "m_pmfxENC->EncodeFrameAsync failed");    if (m_pmfxVPP)    {// 得到视频预处理器的输出        // loop to get buffered frames from vpp        while (MFX_ERR_NONE <= sts || MFX_ERR_MORE_DATA == sts || MFX_ERR_MORE_SURFACE == sts)            // MFX_ERR_MORE_SURFACE can be returned only by RunFrameVPPAsync            // MFX_ERR_MORE_DATA is accepted only from EncodeFrameAsync        {            // find free surface for encoder input (vpp output)            nEncSurfIdx = GetFreeSurface(m_pEncSurfaces, m_EncResponse.NumFrameActual);            MSDK_CHECK_ERROR(nEncSurfIdx, MSDK_INVALID_SURF_IDX, MFX_ERR_MEMORY_ALLOC);            for (;;)            {                sts = m_pmfxVPP->RunFrameVPPAsync(NULL, &m_pEncSurfaces[nEncSurfIdx], NULL, &VppSyncPoint);                if (MFX_ERR_NONE < sts && !VppSyncPoint) // repeat the call if warning and no output                {                    if (MFX_WRN_DEVICE_BUSY == sts)                        MSDK_SLEEP(1); // wait if device is busy                }                else if (MFX_ERR_NONE < sts && VppSyncPoint)                {                    sts = MFX_ERR_NONE; // ignore warnings if output is available                    break;                }                else                    break; // not a warning            }            if (MFX_ERR_MORE_SURFACE == sts)            {                continue;            }            else            {                MSDK_BREAK_ON_ERROR(sts);            }            // get a free task (bit stream and sync point for encoder)            sts = GetFreeTask(&pCurrentTask);            MSDK_BREAK_ON_ERROR(sts);            // save the id of preceding vpp task which will produce input data for the encode task            if (VppSyncPoint)            {                pCurrentTask->DependentVppTasks.push_back(VppSyncPoint);                VppSyncPoint = NULL;            }            for (;;)            {                InsertIDR(m_bInsertIDR);                sts = m_pmfxENC->EncodeFrameAsync(&m_encCtrl, &m_pEncSurfaces[nEncSurfIdx], &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);                m_bInsertIDR = false;                if (MFX_ERR_NONE < sts && !pCurrentTask->EncSyncP) // repeat the call if warning and no output                {                    if (MFX_WRN_DEVICE_BUSY == sts)                        MSDK_SLEEP(1); // wait if device is busy                }                else if (MFX_ERR_NONE < sts && pCurrentTask->EncSyncP)                {                    sts = MFX_ERR_NONE; // ignore warnings if output is available                    break;                }                else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)                {                    sts = AllocateSufficientBuffer(&pCurrentTask->mfxBS);                    MSDK_CHECK_STATUS(sts, "AllocateSufficientBuffer failed");                }                else                {                    // get next surface and new task for 2nd bitstream in ViewOutput mode                    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_BITSTREAM);                    break;                }            }        }        // MFX_ERR_MORE_DATA is the correct status to exit buffering loop with        // indicates that there are no more buffered frames        MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);        // exit in case of other errors        MSDK_CHECK_STATUS(sts, "m_pmfxENC->EncodeFrameAsync failed");    }/*** 这个循环的目的是等待编码器的输出,和上一个循环一样,也是调用EncodeFrameAsync函数,但是参数不一样,请注意** 这个循环一直执行,直到所有的帧都编码完成*/    // loop to get buffered frames from encoder    while (MFX_ERR_NONE <= sts)    {        // get a free task (bit stream and sync point for encoder)        sts = GetFreeTask(&pCurrentTask);        MSDK_BREAK_ON_ERROR(sts);        for (;;)        {            InsertIDR(m_bInsertIDR);            sts = m_pmfxENC->EncodeFrameAsync(&m_encCtrl, NULL, &pCurrentTask->mfxBS, &pCurrentTask->EncSyncP);            m_bInsertIDR = false;            if (MFX_ERR_NONE < sts && !pCurrentTask->EncSyncP) // repeat the call if warning and no output            {                if (MFX_WRN_DEVICE_BUSY == sts)                    MSDK_SLEEP(1); // wait if device is busy            }            else if (MFX_ERR_NONE < sts && pCurrentTask->EncSyncP)            {                sts = MFX_ERR_NONE; // ignore warnings if output is available                break;            }            else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)            {                sts = AllocateSufficientBuffer(&pCurrentTask->mfxBS);                MSDK_CHECK_STATUS(sts, "AllocateSufficientBuffer failed");            }            else            {                // get new task for 2nd bitstream in ViewOutput mode                MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_BITSTREAM);                break;            }        }        MSDK_BREAK_ON_ERROR(sts);    }    // MFX_ERR_MORE_DATA is the correct status to exit buffering loop with    // indicates that there are no more buffered frames    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);    // exit in case of other errors    MSDK_CHECK_STATUS(sts, "m_pmfxENC->EncodeFrameAsync failed");    // synchronize all tasks that are left in task pool    while (MFX_ERR_NONE == sts)    {        sts = m_TaskPool.SynchronizeFirstTask();    }    // MFX_ERR_NOT_FOUND is the correct status to exit the loop with    // EncodeFrameAsync and SyncOperation don't return this status    MSDK_IGNORE_MFX_STS(sts, MFX_ERR_NOT_FOUND);    // report any errors that occurred in asynchronous part    MSDK_CHECK_STATUS(sts, "m_TaskPool.SynchronizeFirstTask failed");    m_statOverall.StopTimeMeasurement();    return sts;}


1 0
原创粉丝点击