硬件编解码(七)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
- 硬件编解码(七)Intel提供的QuickSync使用样例(4)视频编码
- 硬件编解码(三)Intel提供的QuickSync使用样例(1)入门
- 硬件编解码(四)Intel提供的QuickSync使用样例(1)主函数
- 硬件编解码(六)Intel提供的QuickSync使用样例(3)编码器初始化
- 硬件编解码(五)Intel提供的QuickSync使用样例(2)相关数据结构的介绍
- 硬件编解码(三)QuickSync
- 硬件编解码(七)【Intel(R)_Media_SDK】官方文档翻译摘要
- 视频硬件编解码
- 【H.264/AVC视频编解码技术详解】七、 熵编码算法(1):基础知识
- 硬件编解码(一)硬件编解码介绍
- 视频监控行业G711编解码[续]编码样例
- 嵌入式Linux下基于FFmpeg的视频硬件编解码
- 嵌入式Linux下基于FFmpeg的视频硬件编解码
- 嵌入式Linux下基于FFmpeg的视频硬件编解码
- 硬件编解码(八)其他资料的搜集
- 硬件编解码(二)MediaCodec
- (转载)视频编解码学习之四:视频处理及编码标准
- 视频编解码的学习(3)——信息论
- nginx502错误
- zabbix一键安装脚本
- Linux笔试题
- 并发连接数、请求数、并发用户数
- CS231n第一节
- 硬件编解码(七)Intel提供的QuickSync使用样例(4)视频编码
- 一个想法照进现实-《IT连》创业项目:万事开头难
- 页面传值乱码问题
- 获取屏幕的宽高 dp与px转换
- CentOS6.5下Zabbix安装部署及汉化
- webView最全的介绍
- python3 openpyxl
- mysql 数据库表分区
- Zabbix 使用yum快速安装