接上一篇:https://blog.csdn.net/y601500359/article/details/87260201
接下来开始剖析数据解码函数:RunDecoding
- 初始化变量,不细说:
2、下面while循环里是为了循环解码数据帧
while (((sts == MFX_ERR_NONE) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) && (m_nFrames > m_output_count))
{
.........
}
3、接下来依次剖析while循环里面的代码行:
(1)、在循环时,判断如果一旦输出解码数据(m_error = DeliverOutput(frame);)出错,立即跳出循环
if (MFX_ERR_NONE != m_error) {
msdk_printf(MSDK_STRING("DeliverOutput return error = %d\n"),m_error);
break;
}
(2)、在文件播放是,如果数据帧不足一帧,读取下一部分数据:
if (pBitstream && ((MFX_ERR_MORE_DATA == sts) || (m_bIsCompleteFrame && !pBitstream->DataLength))) {
CAutoTimer timer_fread(m_tick_fread);
sts = m_FileReader->ReadNextFrame(pBitstream); // read more data to input bit stream
if (MFX_ERR_MORE_DATA == sts) {
sts = MFX_ERR_NONE;
// Timeout has expired or videowall mode
m_timer_overall.Sync();
if ( ((CTimer::ConvertToSeconds(m_tick_overall) < m_nTimeout) && m_nTimeout ) || m_bIsVideoWall)
{
m_FileReader->Reset();
m_bResetFileWriter = true;
continue;
}
// we almost reached end of stream, need to pull buffered data now
pBitstream = NULL;
}
(3)、同步数据表面:
if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
SyncFrameSurfaces();
SyncVppFrameSurfaces();
if (!m_pCurrentFreeSurface) {
m_pCurrentFreeSurface = m_FreeSurfacesPool.GetSurface();
}
if (!m_pCurrentFreeVppSurface) {
m_pCurrentFreeVppSurface = m_FreeVppSurfacesPool.GetSurface();
}
#ifndef __SYNC_WA
if (!m_pCurrentFreeSurface || !m_pCurrentFreeVppSurface) {
#else
if (!m_pCurrentFreeSurface || (!m_pCurrentFreeVppSurface && m_bVppIsUsed) || (m_OutputSurfacesPool.GetSurfaceCount() == m_mfxVideoParams.AsyncDepth)) {
#endif
// we stuck with no free surface available, now we will sync...
sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
if (MFX_ERR_MORE_DATA == sts) {
if ((m_eWorkMode == MODE_PERFORMANCE) || (m_eWorkMode == MODE_FILE_DUMP)) {
sts = MFX_ERR_NOT_FOUND;
} else if (m_eWorkMode == MODE_RENDERING) {
if (m_synced_count != m_output_count) {
sts = m_pDeliveredEvent->TimedWait(MSDK_DEC_WAIT_INTERVAL);
} else {
sts = MFX_ERR_NOT_FOUND;
}
}
if (MFX_ERR_NOT_FOUND == sts) {
msdk_printf(MSDK_STRING("fatal: failed to find output surface, that's a bug!\n"));
break;
}
}
// note: MFX_WRN_IN_EXECUTION will also be treated as an error at this point
continue;
}
if (!m_pCurrentFreeOutputSurface)
{
m_pCurrentFreeOutputSurface = GetFreeOutputSurface();
}
if (!m_pCurrentFreeOutputSurface)
{
sts = MFX_ERR_NOT_FOUND;
break;
}
}
(4)、解码数据:并同步输出表面
if ((MFX_ERR_NONE == sts) || (MFX_ERR_MORE_DATA == sts) || (MFX_ERR_MORE_SURFACE == sts)) {
if (m_bIsCompleteFrame)
{
m_pCurrentFreeSurface->submit = m_timer_overall.Sync();
}
pOutSurface = NULL;
do {
#if (MFX_VERSION >= 1025)
if (pBitstream) {
pDecodeErrorReport = (mfxExtDecodeErrorReport *)GetExtBuffer(pBitstream->ExtParam, pBitstream->NumExtParam, MFX_EXTBUFF_DECODE_ERROR_REPORT);
}
#endif
sts = m_pmfxDEC->DecodeFrameAsync(pBitstream, &(m_pCurrentFreeSurface->frame), &pOutSurface, &(m_pCurrentFreeOutputSurface->syncp));
#if (MFX_VERSION >= 1025)
PrintDecodeErrorReport(pDecodeErrorReport);
#endif
if (pBitstream && MFX_ERR_MORE_DATA == sts && pBitstream->MaxLength == pBitstream->DataLength)
{
mfxStatus stsExt = ExtendMfxBitstream(pBitstream, pBitstream->MaxLength * 2);
MSDK_CHECK_STATUS_SAFE(stsExt, "ExtendMfxBitstream failed", MSDK_SAFE_DELETE(pDeliverThread));
}
if (MFX_WRN_DEVICE_BUSY == sts) {
if (m_bIsCompleteFrame) {
//in low latency mode device busy leads to increasing of latency
//msdk_printf(MSDK_STRING("Warning : latency increased due to MFX_WRN_DEVICE_BUSY\n"));
}
mfxStatus _sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
// note: everything except MFX_ERR_NONE are errors at this point
if (MFX_ERR_NONE == _sts) {
sts = MFX_WRN_DEVICE_BUSY;
} else {
sts = _sts;
if (MFX_ERR_MORE_DATA == sts) {
// we can't receive MFX_ERR_MORE_DATA and have no output - that's a bug
sts = MFX_WRN_DEVICE_BUSY;//MFX_ERR_NOT_FOUND;
}
}
}
} while (MFX_WRN_DEVICE_BUSY == sts);
if (sts > MFX_ERR_NONE) {
// ignoring warnings...
if (m_pCurrentFreeOutputSurface->syncp) {
MSDK_SELF_CHECK(pOutSurface);
// output is available
sts = MFX_ERR_NONE;
} else {
// output is not available
sts = MFX_ERR_MORE_SURFACE;
}
} else if ((MFX_ERR_MORE_DATA == sts) && pBitstream) {
if (m_bIsCompleteFrame && pBitstream->DataLength)
{
// In low_latency mode decoder have to process bitstream completely
msdk_printf(MSDK_STRING("error: Incorrect decoder behavior in low latency mode (bitstream length is not equal to 0 after decoding)\n"));
sts = MFX_ERR_UNDEFINED_BEHAVIOR;
continue;
}
} else if ((MFX_ERR_MORE_DATA == sts) && !pBitstream) {
// that's it - we reached end of stream; now we need to render bufferred data...
do {
sts = SyncOutputSurface(MSDK_DEC_WAIT_INTERVAL);
} while (MFX_ERR_NONE == sts);
MSDK_IGNORE_MFX_STS(sts, MFX_ERR_MORE_DATA);
if (sts) MSDK_PRINT_WRN_MSG(sts, "SyncOutputSurface failed")
while (m_synced_count != m_output_count) {
m_pDeliveredEvent->Wait();
}
break;
} else if (MFX_ERR_INCOMPATIBLE_VIDEO_PARAM == sts) {
bErrIncompatibleVideoParams = true;
// need to go to the buffering loop prior to reset procedure
pBitstream = NULL;
sts = MFX_ERR_NONE;
continue;
}
}
4、SyncOutputSurface函数:
GetSurface:获取链表中的显示表面
SyncOperation:此函数启动执行尚未启动的异步函数,并在指定的异步操作完成之后返回状态码。 如果wait为零,则函数立即返回。注:SyncOperation这个函数要特别注意,因为我在使用时发现部分电脑,在使用该函数时,返回MFX_ERR_UNKNOWN,最后查明原因,操作系统驱动问题,更新到最新后,正常了。
5、DeliverOutput函数:
该函数主要功能是输出,如果是保存文件模式,怎保存yuv数据到文件;如果是渲染模式,则通过D3D渲染。
保存文件:注意是I420格式,Intel media sdk默认解码出来的是NV12格式,WriteNextFrameI420函数里面会进行一个NV12转I420。
if (m_eWorkMode == MODE_FILE_DUMP) {
res = m_pGeneralAllocator->Lock(m_pGeneralAllocator->pthis, frame->Data.MemId, &(frame->Data));
if (MFX_ERR_NONE == res) {
res = m_bOutI420 ? m_FileWriter.WriteNextFrameI420(frame)
: m_FileWriter.WriteNextFrame(frame);
sts = m_pGeneralAllocator->Unlock(m_pGeneralAllocator->pthis, frame->Data.MemId, &(frame->Data));
}
if ((MFX_ERR_NONE == res) && (MFX_ERR_NONE != sts)) {
res = sts;
}
}
渲染模式:需要注意的是,里面的while循环,这个循环必须要,否则渲染的视频画面会出现时快时慢。
else if (m_eWorkMode == MODE_RENDERING) {
#if D3D_SURFACES_SUPPORT
res = m_d3dRender.RenderFrame(frame, m_pGeneralAllocator);
#elif LIBVA_SUPPORT
res = m_hwdev->RenderFrame(frame, m_pGeneralAllocator);
#endif
while( m_delayTicks && (m_startTick + m_delayTicks > msdk_time_get_tick()) )
{
MSDK_SLEEP(0);
};
m_startTick=msdk_time_get_tick();
}
sample就先简要剖析到此。下一篇开始进行实际项目运用。