/*
* $Id$
*
* (C) 2006-2010 see AUTHORS
*
* This file is part of mplayerc.
*
* Mplayerc is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Mplayerc is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "stdafx.h"
#include "DXVADecoderMpeg2.h"
#include "MPCVideoDecFilter.h"
extern "C"
{
#include "FfmpegContext.h"
}
#if 0
#define TRACE_MPEG2 TRACE
#else
#define TRACE_MPEG2(...)
#endif
CDXVADecoderMpeg2::CDXVADecoderMpeg2 (CMPCVideoDecFilter* pFilter, IAMVideoAccelerator* pAMVideoAccelerator, DXVAMode nMode, int nPicEntryNumber)
: CDXVADecoder (pFilter, pAMVideoAccelerator, nMode, nPicEntryNumber)
{
Init();
}
CDXVADecoderMpeg2::CDXVADecoderMpeg2 (CMPCVideoDecFilter* pFilter, IDirectXVideoDecoder* pDirectXVideoDec, DXVAMode nMode, int nPicEntryNumber, DXVA2_ConfigPictureDecode* pDXVA2Config)
: CDXVADecoder (pFilter, pDirectXVideoDec, nMode, nPicEntryNumber, pDXVA2Config)
{
Init();
}
CDXVADecoderMpeg2::~CDXVADecoderMpeg2(void)
{
Flush();
}
void CDXVADecoderMpeg2::Init()
{
memset (&m_PictureParams, 0, sizeof(m_PictureParams));
memset (&m_SliceInfo, 0, sizeof(m_SliceInfo));
memset (&m_QMatrixData, 0, sizeof(m_QMatrixData));
m_nMaxWaiting = 5;
m_wRefPictureIndex[0] = NO_REF_FRAME;
m_wRefPictureIndex[1] = NO_REF_FRAME;
m_nSliceCount = 0;
switch (GetMode())
{
case MPEG2_VLD :
AllocExecuteParams (4);
break;
default :
ASSERT(FALSE);
}
}
// === Public functions
HRESULT CDXVADecoderMpeg2::DecodeFrame (BYTE* pDataIn, UINT nSize, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
{
HRESULT hr;
int nSurfaceIndex;
CComPtr pSampleToDeliver;
int nFieldType;
int nSliceType;
FFMpeg2DecodeFrame (&m_PictureParams, &m_QMatrixData, m_SliceInfo, &m_nSliceCount, m_pFilter->GetAVCtx(),
m_pFilter->GetFrame(), &m_nNextCodecIndex, &nFieldType, &nSliceType, pDataIn, nSize);
// Wait I frame after a flush
if (m_bFlushed && ! m_PictureParams.bPicIntra)
return S_FALSE;
hr = GetFreeSurfaceIndex (nSurfaceIndex, &pSampleToDeliver, rtStart, rtStop);
if (FAILED (hr))
{
ASSERT (hr == VFW_E_NOT_COMMITTED); // Normal when stop playing
return hr;
}
CHECK_HR (BeginFrame(nSurfaceIndex, pSampleToDeliver));
UpdatePictureParams(nSurfaceIndex);
TRACE_MPEG2 ("=> %s %I64d Surf=%d\n", GetFFMpegPictureType(nSliceType), rtStart, nSurfaceIndex);
TRACE_MPEG2("CDXVADecoderMpeg2 : Decode frame %i\n", m_PictureParams.bPicScanMethod);
CHECK_HR (AddExecuteBuffer (DXVA2_PictureParametersBufferType, sizeof(m_PictureParams), &m_PictureParams));
CHECK_HR (AddExecuteBuffer (DXVA2_InverseQuantizationMatrixBufferType, sizeof(m_QMatrixData), &m_QMatrixData));
// Send bitstream to accelerator
CHECK_HR (AddExecuteBuffer (DXVA2_SliceControlBufferType, sizeof (DXVA_SliceInfo)*m_nSliceCount, &m_SliceInfo));
CHECK_HR (AddExecuteBuffer (DXVA2_BitStreamDateBufferType, nSize, pDataIn, &nSize));
// Decode frame
CHECK_HR (Execute());
CHECK_HR (EndFrame(nSurfaceIndex));
AddToStore (nSurfaceIndex, pSampleToDeliver, (m_PictureParams.bPicBackwardPrediction != 1), rtStart, rtStop,
false,(FF_FIELD_TYPE)nFieldType, (FF_SLICE_TYPE)nSliceType, FFGetCodedPicture(m_pFilter->GetAVCtx()));
m_bFlushed = false;
return DisplayNextFrame();
}
void CDXVADecoderMpeg2::UpdatePictureParams(int nSurfaceIndex)
{
DXVA2_ConfigPictureDecode* cpd = GetDXVA2Config(); // Ok for DXVA1 too (parameters have been copied)
m_PictureParams.wDecodedPictureIndex = nSurfaceIndex;
// Manage reference picture list
if (!m_PictureParams.bPicBackwardPrediction)
{
if (m_wRefPictureIndex[0] != NO_REF_FRAME) RemoveRefFrame (m_wRefPictureIndex[0]);
m_wRefPictureIndex[0] = m_wRefPictureIndex[1];
m_wRefPictureIndex[1] = nSurfaceIndex;
}
m_PictureParams.wForwardRefPictureIndex = (m_PictureParams.bPicIntra == 0) ? m_wRefPictureIndex[0] : NO_REF_FRAME;
m_PictureParams.wBackwardRefPictureIndex = (m_PictureParams.bPicBackwardPrediction == 1) ? m_wRefPictureIndex[1] : NO_REF_FRAME;
// Shall be 0 if bConfigResidDiffHost is 0 or if BPP > 8
if (cpd->ConfigResidDiffHost == 0 || m_PictureParams.bBPPminus1 > 7)
m_PictureParams.bPicSpatialResid8 = 0;
else
{
if (m_PictureParams.bBPPminus1 == 7 && m_PictureParams.bPicIntra && cpd->ConfigResidDiffHost)
// Shall be 1 if BPP is 8 and bPicIntra is 1 and bConfigResidDiffHost is 1
m_PictureParams.bPicSpatialResid8 = 1;
else
// Shall be 1 if bConfigSpatialResid8 is 1
m_PictureParams.bPicSpatialResid8 = cpd->ConfigSpatialResid8;
}
// Shall be 0 if bConfigResidDiffHost is 0 or if bConfigSpatialResid8 is 0 or if BPP > 8
if (cpd->ConfigResidDiffHost == 0 || cpd->ConfigSpatialResid8 == 0 || m_PictureParams.bBPPminus1 > 7)
m_PictureParams.bPicOverflowBlocks = 0;
// Shall be 1 if bConfigHostInverseScan is 1 or if bConfigResidDiffAccelerator is 0.
if (cpd->ConfigHostInverseScan == 1 || cpd->ConfigResidDiffAccelerator == 0)
{
m_PictureParams.bPicScanFixed = 1;
if (cpd->ConfigHostInverseScan != 0)
m_PictureParams.bPicScanMethod = 3; // 11 = Arbitrary scan with absolute coefficient address.
else if (FFGetAlternateScan(m_pFilter->GetAVCtx()))
m_PictureParams.bPicScanMethod = 1; // 00 = Zig-zag scan (MPEG-2 Figure 7-2)
else
m_PictureParams.bPicScanMethod = 0; // 01 = Alternate-vertical (MPEG-2 Figure 7-3),
}
}
void CDXVADecoderMpeg2::SetExtraData (BYTE* pDataIn, UINT nSize)
{
m_PictureParams.wPicWidthInMBminus1 = m_pFilter->PictWidth() - 1;
m_PictureParams.wPicHeightInMBminus1 = m_pFilter->PictHeight() - 1;
}
void CDXVADecoderMpeg2::CopyBitstream(BYTE* pDXVABuffer, BYTE* pBuffer, UINT& nSize)
{
int nDummy;
while (*((DWORD*)pBuffer) != 0x01010000)
{
pBuffer++;
nSize--;
if (nSize <= 0) return;
}
memcpy (pDXVABuffer, pBuffer, nSize);
}
void CDXVADecoderMpeg2::Flush()
{
m_nNextCodecIndex = INT_MIN;
if (m_wRefPictureIndex[0] != NO_REF_FRAME) RemoveRefFrame (m_wRefPictureIndex[0]);
if (m_wRefPictureIndex[1] != NO_REF_FRAME) RemoveRefFrame (m_wRefPictureIndex[1]);
m_wRefPictureIndex[0] = NO_REF_FRAME;
m_wRefPictureIndex[1] = NO_REF_FRAME;
__super::Flush();
}
int CDXVADecoderMpeg2::FindOldestFrame()
{
int nPos = -1;
for (int i=0; iUpdateFrameTime(m_pPictureStore[nPos].rtStart, m_pPictureStore[nPos].rtStop);
return nPos;
}