/*
* $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 "DXVADecoderVC1.h"
#include "MPCVideoDecFilter.h"
extern "C"
{
#include "FfmpegContext.h"
}
#if 0
#define TRACE_VC1 TRACE
#else
#define TRACE_VC1(...)
#endif
inline void SwapRT(REFERENCE_TIME& rtFirst, REFERENCE_TIME& rtSecond)
{
REFERENCE_TIME rtTemp = rtFirst;
rtFirst = rtSecond;
rtSecond = rtTemp;
}
CDXVADecoderVC1::CDXVADecoderVC1 (CMPCVideoDecFilter* pFilter, IAMVideoAccelerator* pAMVideoAccelerator, DXVAMode nMode, int nPicEntryNumber)
: CDXVADecoder (pFilter, pAMVideoAccelerator, nMode, nPicEntryNumber)
{
Init();
}
CDXVADecoderVC1::CDXVADecoderVC1 (CMPCVideoDecFilter* pFilter, IDirectXVideoDecoder* pDirectXVideoDec, DXVAMode nMode, int nPicEntryNumber, DXVA2_ConfigPictureDecode* pDXVA2Config)
: CDXVADecoder (pFilter, pDirectXVideoDec, nMode, nPicEntryNumber, pDXVA2Config)
{
Init();
}
CDXVADecoderVC1::~CDXVADecoderVC1(void)
{
Flush();
}
void CDXVADecoderVC1::Init()
{
memset (&m_PictureParams, 0, sizeof(m_PictureParams));
memset (&m_SliceInfo, 0, sizeof(m_SliceInfo));
m_nMaxWaiting = 5;
m_wRefPictureIndex[0] = NO_REF_FRAME;
m_wRefPictureIndex[1] = NO_REF_FRAME;
switch (GetMode())
{
case VC1_VLD :
AllocExecuteParams (3);
break;
default :
ASSERT(FALSE);
}
}
// === Public functions
HRESULT CDXVADecoderVC1::DecodeFrame (BYTE* pDataIn, UINT nSize, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop)
{
HRESULT hr;
int nSurfaceIndex;
CComPtr pSampleToDeliver;
int nFieldType;
int nSliceType;
FFVC1UpdatePictureParam (&m_PictureParams, m_pFilter->GetAVCtx(), &nFieldType, &nSliceType, pDataIn, nSize);
if (FFIsSkipped (m_pFilter->GetAVCtx()))
return S_OK;
// 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));
TRACE_VC1 ("=> %s %I64d Surf=%d\n", GetFFMpegPictureType(nSliceType), rtStart, nSurfaceIndex);
m_PictureParams.wDecodedPictureIndex = nSurfaceIndex;
m_PictureParams.wDeblockedPictureIndex = m_PictureParams.wDecodedPictureIndex;
// 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;
m_PictureParams.bPic4MVallowed = (m_PictureParams.wBackwardRefPictureIndex == NO_REF_FRAME && m_PictureParams.bPicStructure == 3) ? 1 : 0;
m_PictureParams.bPicDeblockConfined |= (m_PictureParams.wBackwardRefPictureIndex == NO_REF_FRAME) ? 0x04 : 0;
m_PictureParams.bPicScanMethod++; // Use for status reporting sections 3.8.1 and 3.8.2
TRACE_VC1("CDXVADecoderVC1 : Decode frame %i\n", m_PictureParams.bPicScanMethod);
// Send picture params to accelerator
m_PictureParams.wDecodedPictureIndex = nSurfaceIndex;
CHECK_HR (AddExecuteBuffer (DXVA2_PictureParametersBufferType, sizeof(m_PictureParams), &m_PictureParams));
// CHECK_HR (Execute());
// Send bitstream to accelerator
CHECK_HR (AddExecuteBuffer (DXVA2_BitStreamDateBufferType, nSize, pDataIn, &nSize));
m_SliceInfo.wQuantizerScaleCode = 1; // TODO : 1->31 ???
m_SliceInfo.dwSliceBitsInBuffer = nSize * 8;
CHECK_HR (AddExecuteBuffer (DXVA2_SliceControlBufferType, sizeof (m_SliceInfo), &m_SliceInfo));
// Decode frame
CHECK_HR (Execute());
CHECK_HR (EndFrame(nSurfaceIndex));
#ifdef _DEBUG
DisplayStatus();
#endif
// Re-order B frames
if (m_pFilter->IsReorderBFrame())
{
if (m_PictureParams.bPicBackwardPrediction == 1)
{
SwapRT (rtStart, m_rtStartDelayed);
SwapRT (rtStop, m_rtStopDelayed);
}
else
{
// Save I or P reference time (swap later)
if (!m_bFlushed)
{
if (m_nDelayedSurfaceIndex != -1)
UpdateStore (m_nDelayedSurfaceIndex, m_rtStartDelayed, m_rtStopDelayed);
m_rtStartDelayed = m_rtStopDelayed = _I64_MAX;
SwapRT (rtStart, m_rtStartDelayed);
SwapRT (rtStop, m_rtStopDelayed);
m_nDelayedSurfaceIndex = nSurfaceIndex;
}
}
}
AddToStore (nSurfaceIndex, pSampleToDeliver, (m_PictureParams.bPicBackwardPrediction != 1), rtStart, rtStop,
false,(FF_FIELD_TYPE)nFieldType, (FF_SLICE_TYPE)nSliceType, 0);
m_bFlushed = false;
return DisplayNextFrame();
}
void CDXVADecoderVC1::SetExtraData (BYTE* pDataIn, UINT nSize)
{
m_PictureParams.wPicWidthInMBminus1 = m_pFilter->PictWidth() - 1;
m_PictureParams.wPicHeightInMBminus1 = m_pFilter->PictHeight() - 1;
m_PictureParams.bMacroblockWidthMinus1 = 15;
m_PictureParams.bMacroblockHeightMinus1 = 15;
m_PictureParams.bBlockWidthMinus1 = 7;
m_PictureParams.bBlockHeightMinus1 = 7;
m_PictureParams.bBPPminus1 = 7;
m_PictureParams.bMVprecisionAndChromaRelation = 0;
m_PictureParams.bChromaFormat = VC1_CHROMA_420;
m_PictureParams.bPicScanFixed = 0; // Use for status reporting sections 3.8.1 and 3.8.2
m_PictureParams.bPicReadbackRequests = 0;
m_PictureParams.bRcontrol = 0;
m_PictureParams.bPicExtrapolation = 0;
m_PictureParams.bPicDeblocked = 2; // TODO ???
m_PictureParams.bPicOBMC = 0;
m_PictureParams.bPicBinPB = 0; // TODO
m_PictureParams.bMV_RPS = 0; // TODO
m_PictureParams.bReservedBits = 0;
// iWMV9 - i9IRU - iOHIT - iINSO - iWMVA - 0 - 0 - 0 | Section 3.2.5
m_PictureParams.bBidirectionalAveragingMode = (1 << 7) |
(GetConfigIntraResidUnsigned() <<6) | // i9IRU
(GetConfigResidDiffAccelerator() <<5); // iOHIT
}
BYTE* CDXVADecoderVC1::FindNextStartCode(BYTE* pBuffer, UINT nSize, UINT& nPacketSize)
{
BYTE* pStart = pBuffer;
BYTE bCode = 0;
for (int i=0; i= nSize-5) )
{
if (bCode == 0)
{
bCode = pBuffer[i+3];
if ((nSize == 5) && (bCode == 0x0D))
{
nPacketSize = nSize;
return pBuffer;
}
}
else
{
if (bCode == 0x0D)
{
// Start code found!
nPacketSize = i - (pStart - pBuffer) + (i >= nSize-5 ? 5 : 1);
return pStart;
}
else
{
// Other stuff, ignore it
pStart = pBuffer + i;
bCode = pBuffer[i+3];
}
}
}
}
ASSERT (FALSE); // Should never happen!
return NULL;
}
void CDXVADecoderVC1::CopyBitstream(BYTE* pDXVABuffer, BYTE* pBuffer, UINT& nSize)
{
int nDummy;
if ( (*((DWORD*)pBuffer) & 0x00FFFFFF) != 0x00010000)
{
// Some splitter have remove startcode (Haali)
pDXVABuffer[0]=pDXVABuffer[1]=0;
pDXVABuffer[2]=1;
pDXVABuffer[3]=0x0D;
pDXVABuffer +=4;
// Copy bitstream buffer, with zero padding (buffer is rounded to multiple of 128)
memcpy (pDXVABuffer, (BYTE*)pBuffer, nSize);
nSize +=4;
}
else
{
BYTE* pStart;
UINT nPacketSize;
pStart = FindNextStartCode (pBuffer, nSize, nPacketSize);
if (pStart)
{
// Startcode already present
memcpy (pDXVABuffer, (BYTE*)pStart, nPacketSize);
nSize = nPacketSize;
}
}
nDummy = 128 - (nSize %128);
pDXVABuffer += nSize;
memset (pDXVABuffer, 0, nDummy);
nSize += nDummy;
}
void CDXVADecoderVC1::Flush()
{
m_nDelayedSurfaceIndex = -1;
m_rtStartDelayed = _I64_MAX;
m_rtStopDelayed = _I64_MAX;
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();
}
HRESULT CDXVADecoderVC1::DisplayStatus()
{
HRESULT hr = E_INVALIDARG;
DXVA_Status_VC1 Status;
memset (&Status, 0, sizeof(Status));
if (SUCCEEDED (hr = CDXVADecoder::QueryStatus(&Status, sizeof(Status))))
{
Status.StatusReportFeedbackNumber = 0x00FF & Status.StatusReportFeedbackNumber;
TRACE_VC1 ("CDXVADecoderVC1 : Status for the frame %u : bBufType = %u, bStatus = %u, wNumMbsAffected = %u\n",
Status.StatusReportFeedbackNumber,
Status.bBufType,
Status.bStatus,
Status.wNumMbsAffected);
}
return hr;
}