1
0
Fork 0

git-svn-id: svn://svn.code.sf.net/p/qsdecoder/code/trunk/IntelQuickSyncDecoder@9 dfccccb7-dd81-40b7-a334-5a7ba89c2b1d

This commit is contained in:
egur 2011-12-29 22:50:27 +00:00
parent e1c96fc123
commit f69a0e60a7
15 changed files with 768 additions and 313 deletions

View File

@ -29,7 +29,7 @@
#pragma once
#define QS_DEC_DLL_NAME "IntelQuickSyncDecoder.dll"
#define QS_DEC_VERSION "v0.20 Alpha"
#define QS_DEC_VERSION "v0.21 Beta"
// Forward declarations
struct IDirect3DDeviceManager9;
@ -89,12 +89,12 @@ struct CQsConfig
unsigned codecs;
struct
{
bool bEnableDvdDecoding : 1;
bool bEnableH264 : 1;
bool bEnableMPEG2 : 1;
bool bEnableVC1 : 1;
bool bEnableWMV9 : 1;
unsigned reserved2 : 27;
bool bEnableDvdDecoding : 1;
bool bEnableH264 : 1;
bool bEnableMPEG2 : 1;
bool bEnableVC1 : 1;
bool bEnableWMV9 : 1;
unsigned reserved2 : 27;
};
};
};

85
IntelQuickSyncDecoder.rc Normal file
View File

@ -0,0 +1,85 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_RESOURCE_DLL)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,21,0,0
PRODUCTVERSION 0,21,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Intel Corp."
VALUE "FileDescription", "IntelQuickSyncDecoder DLL"
VALUE "FileVersion", "0.21 Beta"
VALUE "InternalName", "IntelQuickSyncDecoder"
VALUE "LegalCopyright", "BSD lisence. © 2011 Intel ® Corp."
VALUE "LegalTrademarks", "Intel QuickSync"
VALUE "OriginalFilename", "IntelQuickSyncDecoder.dll"
VALUE "ProductName", "IntelQuickSyncDecoder"
VALUE "ProductVersion", "0.21 Beta"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

26
IntelQuickSyncDecoder.sln Normal file
View File

@ -0,0 +1,26 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IntelQuickSyncDecoder", "IntelQuickSyncDecoder.vcxproj", "{83F0170E-6AB3-467B-98D5-E061BD2BF00D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Debug|Win32.ActiveCfg = Debug|Win32
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Debug|Win32.Build.0 = Debug|Win32
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Debug|x64.ActiveCfg = Debug|x64
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Debug|x64.Build.0 = Debug|x64
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Release|Win32.ActiveCfg = Release|Win32
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Release|Win32.Build.0 = Release|Win32
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Release|x64.ActiveCfg = Release|x64
{83F0170E-6AB3-467B-98D5-E061BD2BF00D}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -242,6 +242,7 @@
<ClInclude Include="QuickSync.h" />
<ClInclude Include="QuickSyncUtils.h" />
<ClInclude Include="QuickSync_defs.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="sysmem_allocator.h" />
<ClInclude Include="TimeManager.h" />
@ -264,6 +265,9 @@
<ClCompile Include="sysmem_allocator.cpp" />
<ClCompile Include="TimeManager.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="IntelQuickSyncDecoder.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -9,6 +9,9 @@
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{0a386d10-f3de-44fa-855a-fa02aa8f04c8}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h">
@ -50,6 +53,9 @@
<ClInclude Include="CodecInfo.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -90,4 +96,9 @@
<None Include="license.txt" />
<None Include="IntelQuickSyncDecoder.def" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="IntelQuickSyncDecoder.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@ -31,12 +31,13 @@
#include "QuickSync_defs.h"
#include "CodecInfo.h"
#include "TimeManager.h"
#include "QuickSyncDecoder.h"
#include "frame_constructors.h"
#include "QuickSyncUtils.h"
#include "frame_constructors.h"
#include "QuickSyncDecoder.h"
#include "QuickSync.h"
#define PAGE_MASK 4095
#define TM_PROCESS_FRAME (WM_USER + 1)
EXTERN_GUID(WMMEDIASUBTYPE_WVC1,
0x31435657, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
@ -52,13 +53,14 @@ DEFINE_GUID(WMMEDIASUBTYPE_WVC1_PDVD,
CQuickSync::CQuickSync() :
m_nPitch(0),
m_pFrameConstructor(NULL),
m_OutputBuffer(NULL),
m_OutputBufferSize(0),
m_nSegmentFrameCount(0),
m_bFlushing(false),
m_bNeedToFlush(false),
m_bForceOutput(false),
m_bDvdDecoding(false)
m_bDvdDecoding(false),
m_hWorkerThread(NULL),
m_WorkerThreadId(0),
m_WorkerThreadIsRunning(false)
{
MSDK_TRACE("QSDcoder: Constructor\n");
@ -86,12 +88,26 @@ CQuickSync::CQuickSync() :
CQuickSync::~CQuickSync()
{
MSDK_TRACE("QSDcoder: Destructor\n");
// This will quicken the exit
m_bNeedToFlush = true;
CQsAutoLock cObjectLock(&m_csLock);
if (m_WorkerThreadId)
{
PostThreadMessage(m_WorkerThreadId, WM_QUIT, 0, 0);
WaitForSingleObject(m_hWorkerThread, INFINITE);
}
while (!m_FreeFramesPool.Empty())
{
TQsQueueItem item = m_FreeFramesPool.Pop();
delete item.second;
}
MSDK_SAFE_DELETE(m_pFrameConstructor);
MSDK_SAFE_DELETE(m_pDecoder);
_aligned_free(m_OutputBuffer);
}
HRESULT CQuickSync::HandleSubType(const GUID& subType, FOURCC fourCC)
@ -114,7 +130,7 @@ HRESULT CQuickSync::HandleSubType(const GUID& subType, FOURCC fourCC)
{
m_mfxParamsVideo.mfx.CodecId = MFX_CODEC_VC1;
if (subType == WMMEDIASUBTYPE_WMV3)
if (subType == WMMEDIASUBTYPE_WMV3)
{
m_mfxParamsVideo.mfx.CodecProfile = MFX_PROFILE_VC1_SIMPLE;
if (!m_Config.bEnableWMV9)
@ -276,9 +292,11 @@ HRESULT CQuickSync::InitDecoder(const AM_MEDIA_TYPE* mtIn, FOURCC fourCC)
hr = CopyMediaTypeToVIDEOINFOHEADER2(mtIn, vih2, nVideoInfoSize, nSampleSize);
MSDK_CHECK_RESULT_P_RET(hr, S_OK);
if (MEDIATYPE_DVD_ENCRYPTED_PACK == mtIn->majortype)
{
if (!m_Config.bEnableDvdDecoding)
return VFW_E_INVALIDMEDIATYPE;
m_pFrameConstructor->SetDvdPacketStripping(true);
m_bDvdDecoding = true;
}
@ -370,6 +388,24 @@ HRESULT CQuickSync::InitDecoder(const AM_MEDIA_TYPE* mtIn, FOURCC fourCC)
m_pDecoder->SetConfig(m_Config);
}
// This is constant
m_FrameDataTemplate.fourCC = FOURCC_NV12;
// Create worker thread
m_hWorkerThread = (HANDLE)_beginthreadex(NULL, 0, &WorkerThreadProc, this, 0, &m_WorkerThreadId);
// Fill free frames pool
{
size_t queueCapacity = 4;
m_FreeFramesPool.SetCapacity(queueCapacity);
m_ProcessedFramesQueue.SetCapacity(queueCapacity);
for (unsigned i = 0; i < queueCapacity; ++i)
{
TQsQueueItem item(m_FrameDataTemplate, new CQsAlignedBuffer(0));
m_FreeFramesPool.Push(item);
}
}
done:
delete[] (mfxU8*)vih2;
m_OK = (sts == MFX_ERR_NONE);
@ -403,13 +439,13 @@ void CQuickSync::SetAspectRatio(VIDEOINFOHEADER2& vih2, mfxFrameInfo& frameInfo)
// use image size as aspect ratio when PAR is 1x1
if (frameInfo.AspectRatioW == frameInfo.AspectRatioH)
{
m_FrameData.dwPictAspectRatioX = alignedWidth;
m_FrameData.dwPictAspectRatioY = frameInfo.CropH;
m_FrameDataTemplate.dwPictAspectRatioX = alignedWidth;
m_FrameDataTemplate.dwPictAspectRatioY = frameInfo.CropH;
}
else
{
m_FrameData.dwPictAspectRatioX = vih2.dwPictAspectRatioX;
m_FrameData.dwPictAspectRatioY = vih2.dwPictAspectRatioY;
m_FrameDataTemplate.dwPictAspectRatioX = vih2.dwPictAspectRatioX;
m_FrameDataTemplate.dwPictAspectRatioY = vih2.dwPictAspectRatioY;
}
}
@ -431,7 +467,7 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
CQsAutoLock cObjectLock(&m_csLock);
MSDK_TRACE("QSDcoder: Decode\n");
MSDK_VTRACE("QSDcoder: Decode\n");
// We haven't flushed since the last BeginFlush call - probably a DVD playback scenario
// where NewSegment/OnSeek isn't issued.
@ -440,6 +476,17 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
OnSeek(0);
}
// Wait for worker thread to become less busy (free pool not empty)
while (m_FreeFramesPool.Empty())
{
if (m_bNeedToFlush)
{
return S_OK;
}
Sleep(1);
}
MSDK_CHECK_NOT_EQUAL(m_OK, true, E_UNEXPECTED);
HRESULT hr = S_OK;
mfxStatus sts = MFX_ERR_NONE;
@ -458,8 +505,6 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
return S_FALSE;
}
m_TimeManager.AddTimeStamp(pSample);
// Manipulate bitstream for decoder
sts = m_pFrameConstructor->ConstructFrame(pSample, &mfxBS);
ASSERT(mfxBS.DataLength <= mfxBS.MaxLength);
@ -475,7 +520,9 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
if (MFX_ERR_NONE == sts)
{
DeliverSurface(pSurfaceOut);
// Lock the surface so it will not be used by decoder->FindFreeSurface
m_pDecoder->LockSurface(pSurfaceOut);
QueueSurface(pSurfaceOut);
continue;
}
else if (MFX_ERR_MORE_DATA == sts)
@ -506,7 +553,7 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
else if (MFX_ERR_NOT_ENOUGH_BUFFER == sts)
{
MSDK_TRACE("QSDcoder: Decode MFX_ERR_NOT_ENOUGH_BUFFER\n");
if (!m_pDecoder->GetOutputQueue()->empty())
if (!m_pDecoder->OutputQueueEmpty())
{
FlushOutputQueue(true);
continue;
@ -554,194 +601,49 @@ HRESULT CQuickSync::Decode(IMediaSample* pSample)
m_pFrameConstructor->SaveResidialData(&mfxBS);
MSDK_SAFE_DELETE_ARRAY(mfxBS.Data);
// Deliver the samres we already processed
DeliverSurface(false);
return hr;
}
HRESULT CQuickSync::DeliverSurface(mfxFrameSurface1* pSurface)
HRESULT CQuickSync::DeliverSurface(bool bWaitForCompletion)
{
if (m_bNeedToFlush)
return S_OK;
MSDK_VTRACE("QSDcoder: DeliverSurface\n");
MSDK_TRACE("QSDcoder: DeliverSurface\n");
MSDK_CHECK_POINTER(m_DeliverSurfaceCallback, E_UNEXPECTED);
m_FrameData.fourCC = FOURCC_NV12;
// Got a new surface. A NULL surface means to get a surface from the output queue
if (pSurface != NULL)
// Output a free if any are available or wait wait for one to become available if reuqested (bWaitForCompletion)
while (!m_ProcessedFramesQueue.Empty() ||
(bWaitForCompletion && m_FreeFramesPool.HasCapacity()))
{
// Initial frames with invalid times are discarded
REFERENCE_TIME rtStart = m_TimeManager.ConvertMFXTime2ReferenceTime(pSurface->Data.TimeStamp);
if (m_pDecoder->GetOutputQueue()->empty() && rtStart == INVALID_REFTIME)
return S_OK;
PushSurface(pSurface);
// Not enough surfaces for proper time stamp correction
DWORD queueSize = (m_bDvdDecoding) ? 0 : m_Config.nOutputQueueLength;
if (!m_bForceOutput && m_pDecoder->GetOutputQueue()->size() < queueSize)
return S_OK;
}
// Get oldest surface from queue
pSurface = PopSurface();
MSDK_CHECK_POINTER(pSurface, E_POINTER);
if (pSurface->Data.Corrupted)
{
// Do something with a corrupted surface?
pSurface->Data.Corrupted = pSurface->Data.Corrupted;
}
++m_nSegmentFrameCount;
// Result is in m_FrameData
// False return value means that the frame has a negative time stamp and should not be displayed.
if (!SetTimeStamp(pSurface))
return S_OK;
m_FrameData.bFilm = false;
// Setup interlacing info
m_FrameData.dwInterlaceFlags = PicStructToDsFlags(pSurface->Info.PicStruct);
// TODO: find actual frame type I/P/B
// Media sample isn't reliable as it referes to an older frame!
m_FrameData.frameType = QsFrameData::I;
// Obtain surface data and copy it to temp buffer.
mfxFrameData frameData;
m_pDecoder->LockFrame(pSurface, &frameData);
// Setup output buffer
m_FrameData.dwStride = frameData.Pitch;
size_t outSize = 4096 + // Adding 4K for page alignment optimizations
m_FrameData.dwStride * pSurface->Info.CropH * 3 / 2;
if (!m_OutputBuffer || m_OutputBufferSize != outSize)
{
if (m_OutputBuffer)
if (!m_ProcessedFramesQueue.Empty())
{
_aligned_free(m_OutputBuffer);
TQsQueueItem item = m_ProcessedFramesQueue.Pop();
ASSERT(item.second);
QsFrameData& pFrameData = item.first;
if (!m_bNeedToFlush)
{
// Send the surface out - return code from dshow filter is ignored.
MSDK_VTRACE("QSDcoder: DeliverSurfaceCallback (%I64d, %I64d)\n", pFrameData.rtStart, pFrameData.rtStop);
m_DeliverSurfaceCallback(m_ObjParent, &pFrameData);
}
m_FreeFramesPool.Push(item);
}
else
{
Sleep(1);
}
m_OutputBufferSize = outSize;
// malloc with page alignment (easier to offset)
m_OutputBuffer = (BYTE*)_aligned_malloc(m_OutputBufferSize, 16);
if (m_bNeedToFlush)
{
return S_OK;
}
}
size_t height = pSurface->Info.CropH; // Cropped image height
size_t pitch = frameData.Pitch; // Image line + padding in bytes --> set by the driver
// Fill image size
m_FrameData.rcFull.top = m_FrameData.rcFull.left = 0;
m_FrameData.rcFull.bottom = (LONG)height - 1;
m_FrameData.rcFull.right = MSDK_ALIGN16(pSurface->Info.CropW + pSurface->Info.CropX) - 1;
m_FrameData.rcClip.top = 0;
m_FrameData.rcClip.bottom = (LONG)height - 1;
if (m_Config.bMod16Width)
{
m_FrameData.rcClip = m_FrameData.rcFull;
}
else
{
m_FrameData.rcClip.left = pSurface->Info.CropX;
m_FrameData.rcClip.right = pSurface->Info.CropW + pSurface->Info.CropX - 1;
}
// Offset output buffer's address for fastest SSE4 copy.
// Page offset (12 lsb of addresses) sould be 2K apart from source buffer
size_t offset = ((size_t)frameData.Y & PAGE_MASK) ^ (1 << 11);
// Source is D3D9 surface
if (m_pDecoder->IsD3DAlloc())
{
m_FrameData.y = m_OutputBuffer + offset;
m_FrameData.u = m_FrameData.y + (pitch * height);
// Copy Y
gpu_memcpy(m_FrameData.y, frameData.Y + (pSurface->Info.CropY * pitch), height * pitch);
// Copy UV
gpu_memcpy(m_FrameData.u, frameData.CbCr + (pSurface->Info.CropY * pitch), pitch * height / 2);
// Add borders for non standard images
//unsigned dwWidth = m_FrameData.rcFull.right + 1;
//if (m_Config.bMod16Width && pSurface->Info.CropW < dwWidth)
//{
// AddBorders(pSurface);
//}
// App can modify this buffer
m_FrameData.bReadOnly = false;
// Debug only - mark top left corner when working withg D3D
#ifdef _DEBUG
memset(m_FrameData.u, 0xff, 4);
#endif
}
// Source is system memory
else
{
m_FrameData.y = frameData.Y + (pSurface->Info.CropY * pitch);
m_FrameData.u = frameData.CbCr + (pSurface->Info.CropY * pitch);
// App can't modify this buffer - cause corruption
m_FrameData.bReadOnly = false;
}
// Unlock the frame
m_pDecoder->UnlockFrame(pSurface, &frameData);
// Send the surface out - return code from dshow filter is ignored.
if (m_bNeedToFlush)
return S_OK;
MSDK_TRACE("QSDcoder: DeliverSurfaceCallback (%I64d, %I64d)\n", m_FrameData.rtStart, m_FrameData.rtStop);
m_DeliverSurfaceCallback(m_ObjParent, &m_FrameData);
return S_OK;
}
void CQuickSync::AddBorders(mfxFrameSurface1* pSurface)
{
int h = (int)m_FrameData.rcClip.bottom + 1;
// Left border
if (pSurface->Info.CropX > 0)
{
for (int y = 0; y < h; ++y)
{
memset(m_FrameData.y + m_FrameData.dwStride * y, 16, pSurface->Info.CropX);
if (y < h / 2)
{
memset(m_FrameData.u + m_FrameData.dwStride * y, 128, pSurface->Info.CropX);
}
}
}
// Right border
int rBorderWidth = (int)m_FrameData.rcFull.right + 1 - (pSurface->Info.CropX + pSurface->Info.CropW);
if (rBorderWidth)
{
for (int y = 0; y < h; ++y)
{
memset(m_FrameData.y + m_FrameData.dwStride * y + pSurface->Info.CropX + pSurface->Info.CropW,
16, rBorderWidth);
if (y < h / 2)
{
memset(m_FrameData.u + m_FrameData.dwStride * y + pSurface->Info.CropX + pSurface->Info.CropW,
128, rBorderWidth);
}
}
}
}
mfxU32 CQuickSync::PicStructToDsFlags(mfxU32 picStruct)
{
if (m_TimeManager.GetInverseTelecine())
@ -818,9 +720,9 @@ HRESULT CQuickSync::Flush(bool deliverFrames)
mfxFrameSurface1* pSurf = NULL;
sts = m_pDecoder->Decode(NULL, pSurf);
if (MFX_ERR_NONE == sts && deliverFrames)
if (MFX_ERR_NONE == sts && deliverFrames && !m_bNeedToFlush)
{
hr = DeliverSurface(pSurf);
hr = QueueSurface(pSurf);
if (FAILED(hr))
break;
}
@ -828,9 +730,7 @@ HRESULT CQuickSync::Flush(bool deliverFrames)
// Flush internal queue again
FlushOutputQueue(deliverFrames);
ASSERT(m_pDecoder->GetOutputQueue()->empty());
m_TimeManager.Reset();
m_bForceOutput = false;
@ -846,31 +746,74 @@ void CQuickSync::FlushOutputQueue(bool deliverFrames)
bool bForceOutputSave = m_bForceOutput;
m_bForceOutput = deliverFrames && !m_bNeedToFlush;
// Note that m_bNeedToFlush can be changed by another thread at any time
if (!deliverFrames || m_bNeedToFlush)
{
ClearQueue();
}
MSDK_TRACE("QSDcoder: FlushOutputQueue (deliverFrames=%s)\n", (m_bForceOutput) ? "TRUE" : "FALSE");
while (!m_pDecoder->GetOutputQueue()->empty() && deliverFrames && !m_bNeedToFlush)
while (!m_pDecoder->OutputQueueEmpty() && deliverFrames && !m_bNeedToFlush)
{
DeliverSurface(NULL);
QueueSurface(NULL);
DeliverSurface(deliverFrames && !m_bNeedToFlush);
}
// clear the internal frame queue - either failure in flushing or no need to deliver the frames.
while (!m_pDecoder->GetOutputQueue()->empty())
// Clear the internal frame queue - either failure in flushing or no need to deliver the frames.
while (!m_pDecoder->OutputQueueEmpty())
{
PopSurface();
mfxFrameSurface1* pSurface = PopSurface();
// Surface is not needed anymore
m_pDecoder->UnlockSurface(pSurface);
}
if (deliverFrames && !m_bNeedToFlush)
{
DeliverSurface(true);
}
else
{
ClearQueue();
}
ASSERT(m_pDecoder->OutputQueueEmpty());
ASSERT(m_ProcessedFramesQueue.Empty());
ASSERT(!m_FreeFramesPool.HasCapacity());
m_bForceOutput = bForceOutputSave;
}
void CQuickSync::ClearQueue()
{
// Loop until free frames pool is full
while (m_FreeFramesPool.HasCapacity())
{
if (m_ProcessedFramesQueue.Empty())
{
Sleep(1);
}
else
{
m_FreeFramesPool.Push(m_ProcessedFramesQueue.Pop());
}
}
}
HRESULT CQuickSync::OnSeek(REFERENCE_TIME segmentStart)
{
MSDK_TRACE("QSDcoder: OnSeek\n");
CQsAutoLock cObjectLock(&m_csLock);
mfxStatus sts = MFX_ERR_NONE;
m_bNeedToFlush = true;
mfxStatus sts = MFX_ERR_NONE;
m_nSegmentFrameCount = 0;
// Make sure the worker thread is idle and released all released all resources
FlushOutputQueue(false);
if (m_pDecoder)
{
m_TimeManager.Reset();
@ -890,13 +833,13 @@ HRESULT CQuickSync::OnSeek(REFERENCE_TIME segmentStart)
return (sts == MFX_ERR_NONE) ? S_OK : E_FAIL;
}
bool CQuickSync::SetTimeStamp(mfxFrameSurface1* pSurface)
bool CQuickSync::SetTimeStamp(mfxFrameSurface1* pSurface, QsFrameData& frameData)
{
if (!m_TimeManager.GetSampleTimeStamp(pSurface, *m_pDecoder->GetOutputQueue(), m_FrameData.rtStart, m_FrameData.rtStop))
if (!m_TimeManager.GetSampleTimeStamp(pSurface, m_pDecoder->GetOutputQueue(), frameData.rtStart, frameData.rtStop))
return false;
//TODO: force BOB DI after loss of IVTC for a few frames
return m_FrameData.rtStart >= 0;
return frameData.rtStart >= 0;
}
mfxStatus CQuickSync::OnVideoParamsChanged()
@ -928,7 +871,8 @@ mfxStatus CQuickSync::OnVideoParamsChanged()
if (bAspectRatioChange || bResChange)
{
DWORD alignedWidth = (m_Config.bMod16Width) ? MSDK_ALIGN16(newInfo.CropW) : newInfo.CropW;
PARtoDAR(newInfo.AspectRatioW, newInfo.AspectRatioH, alignedWidth, newInfo.CropH, m_FrameData.dwPictAspectRatioX, m_FrameData.dwPictAspectRatioY);
PARtoDAR(newInfo.AspectRatioW, newInfo.AspectRatioH, alignedWidth, newInfo.CropH,
m_FrameDataTemplate.dwPictAspectRatioX, m_FrameDataTemplate.dwPictAspectRatioY);
}
if (bFrameRateChange)
@ -1023,3 +967,229 @@ void CQuickSync::SetConfig(CQsConfig* pConfig)
m_Config = *pConfig;
}
unsigned CQuickSync::WorkerThreadProc(void* pThis)
{
ASSERT(pThis != NULL);
return static_cast<CQuickSync*>(pThis)->WorkerThreadMsgLoop();
}
unsigned CQuickSync::WorkerThreadMsgLoop()
{
#ifdef _DEBUG
SetThreadName("*** QS worker ***");
#endif
BOOL bRet;
// Note: GetMessage returns zero on WM_QUIT
MSG msg;
while ((bRet = GetMessage(&msg, (HWND)-1, 0, 0 )) != 0)
{
m_WorkerThreadIsRunning = true;
// Error
if (bRet == -1)
{
return (unsigned) bRet;
}
if (TM_PROCESS_FRAME == msg.message)
{
mfxFrameSurface1* pSurface = (mfxFrameSurface1*)msg.wParam;
HRESULT hr = ProcessDecodedFrame(pSurface);
if (FAILED(hr))
{
// Error
bRet = -1;
break;
}
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
m_WorkerThreadIsRunning = false;
}
m_WorkerThreadIsRunning = false;
// All's well
return 0;
}
HRESULT CQuickSync::QueueSurface(mfxFrameSurface1* pSurface)
{
// Post message to worker thread
PostThreadMessage(m_WorkerThreadId, TM_PROCESS_FRAME, (WPARAM)pSurface, 0);
return S_OK;
}
// This function works on the worker thread
HRESULT CQuickSync::ProcessDecodedFrame(mfxFrameSurface1* pSurface)
{
MSDK_VTRACE("QSDcoder: ProcessDecodedFrame\n");
// Got a new surface. A NULL surface means to get a surface from the output queue
if (pSurface != NULL)
{
// Initial frames with invalid times are discarded
REFERENCE_TIME rtStart = m_TimeManager.ConvertMFXTime2ReferenceTime(pSurface->Data.TimeStamp);
if (m_pDecoder->OutputQueueEmpty() && rtStart == INVALID_REFTIME)
{
m_pDecoder->UnlockSurface(pSurface);
return S_OK;
}
PushSurface(pSurface);
// Not enough surfaces for proper time stamp correction
DWORD queueSize = (m_bDvdDecoding) ? 0 : m_Config.nOutputQueueLength;
if (!m_bForceOutput && m_pDecoder->OutputQueueSize() < queueSize)
{
return S_OK;
}
}
// Get oldest surface from queue
pSurface = PopSurface();
MSDK_CHECK_POINTER(pSurface, S_OK); // decoder queue is empty - return without error
while (m_FreeFramesPool.Empty())
{
if (m_bNeedToFlush)
{
m_pDecoder->UnlockSurface(pSurface);
return S_OK;
}
Sleep(1);
}
TQsQueueItem item = m_FreeFramesPool.Pop();
QsFrameData& outFrameData = item.first;
CQsAlignedBuffer*& pOutBuffer = item.second;
m_FrameDataTemplate = m_FrameDataTemplate;
if (pSurface->Data.Corrupted)
{
// Do something with a corrupted surface?
pSurface->Data.Corrupted = pSurface->Data.Corrupted;
}
++m_nSegmentFrameCount;
// Result is in m_FrameData
// False return value means that the frame has a negative time stamp and should not be displayed.
if (!SetTimeStamp(pSurface, outFrameData))
{
// Return frame to free pool
m_FreeFramesPool.Push(item);
m_pDecoder->UnlockSurface(pSurface);
return S_OK;
}
outFrameData.bFilm = false;
// Setup interlacing info
outFrameData.dwInterlaceFlags = PicStructToDsFlags(pSurface->Info.PicStruct);
// TODO: find actual frame type I/P/B
// Media sample isn't reliable as it referes to an older frame!
outFrameData.frameType = QsFrameData::I;
// Obtain surface data and copy it to temp buffer.
mfxFrameData frameData;
m_pDecoder->LockFrame(pSurface, &frameData);
// Setup output buffer
outFrameData.dwStride = frameData.Pitch;
size_t outSize = 4096 + // Adding 4K for page alignment optimizations
outFrameData.dwStride * pSurface->Info.CropH * 3 / 2;
// Make ure we have a buffer with the right size
if (pOutBuffer->GetBufferSize() < outSize)
{
delete pOutBuffer;
pOutBuffer = new CQsAlignedBuffer(outSize);
}
size_t height = pSurface->Info.CropH; // Cropped image height
size_t pitch = frameData.Pitch; // Image line + padding in bytes --> set by the driver
// Fill image size
outFrameData.rcFull.top = outFrameData.rcFull.left = 0;
outFrameData.rcFull.bottom = (LONG)height - 1;
outFrameData.rcFull.right = MSDK_ALIGN16(pSurface->Info.CropW + pSurface->Info.CropX) - 1;
outFrameData.rcClip.top = 0;
outFrameData.rcClip.bottom = (LONG)height - 1;
if (m_Config.bMod16Width)
{
outFrameData.rcClip = outFrameData.rcFull;
}
else
{
// Note that we always crop the height
outFrameData.rcClip.left = pSurface->Info.CropX;
outFrameData.rcClip.right = pSurface->Info.CropW + pSurface->Info.CropX - 1;
}
// Offset output buffer's address for fastest SSE4 copy.
// Page offset (12 lsb of addresses) sould be 2K apart from source buffer
size_t offset = ((size_t)frameData.Y & PAGE_MASK) ^ (1 << 11);
// Mark Y, U & V pointers on output buffer
outFrameData.y = pOutBuffer->GetBuffer() + offset;
outFrameData.u = outFrameData.y + (pitch * height);
outFrameData.v = outFrameData.u + 1;
// App can modify this buffer
outFrameData.bReadOnly = false;
// Source is D3D9 surface
if (m_pDecoder->IsD3DAlloc())
{
// Copy Y
gpu_memcpy(outFrameData.y, frameData.Y + (pSurface->Info.CropY * pitch), height * pitch);
// Copy UV
gpu_memcpy(outFrameData.u, frameData.CbCr + (pSurface->Info.CropY * pitch), pitch * height / 2);
}
// Source is system memory
else
{
// Copy Y
memcpy(outFrameData.y, frameData.Y + (pSurface->Info.CropY * pitch), height * pitch);
// Copy UV
memcpy(outFrameData.u, frameData.CbCr + (pSurface->Info.CropY * pitch), pitch * height / 2);
}
// Unlock the frame
m_pDecoder->UnlockFrame(pSurface, &frameData);
// We don't need the surface anymore
m_pDecoder->UnlockSurface(pSurface);
#ifdef _DEBUG
// Debug only - mark top left corner when working with D3D
*((REFERENCE_TIME*)outFrameData.u) = (REFERENCE_TIME)(-1); // 4 pink pixels
#endif
// Keep or drop the processed frame
if (!m_bNeedToFlush)
{
// Enter result in the processed queue
m_ProcessedFramesQueue.Push(item);
}
else
{
// Return to free pool
m_FreeFramesPool.Push(item);
}
return S_OK;
}

View File

@ -74,7 +74,10 @@ protected:
virtual void SetD3DDeviceManager(IDirect3DDeviceManager9* pDeviceManager);
HRESULT HandleSubType(const GUID& subType, FOURCC fourCC);
HRESULT CopyMediaTypeToVIDEOINFOHEADER2(const AM_MEDIA_TYPE* mtIn, VIDEOINFOHEADER2*& vih2, size_t& nVideoInfoSize, size_t& nSampleSize);
HRESULT DeliverSurface(mfxFrameSurface1* pSurfaceOut);
HRESULT QueueSurface(mfxFrameSurface1* pSurface);
HRESULT ProcessDecodedFrame(mfxFrameSurface1* pSurface);
void ClearQueue();
HRESULT DeliverSurface(bool bWaitForCompletion);
virtual void SetDeliverSurfaceCallback(void* obj, TQS_DeliverSurfaceCallback func)
{
CQsAutoLock cObjectLock(&m_csLock);
@ -85,7 +88,7 @@ protected:
virtual void GetConfig(CQsConfig* pConfig);
virtual void SetConfig(CQsConfig* pConfig);
bool SetTimeStamp(mfxFrameSurface1* pSurface);
bool SetTimeStamp(mfxFrameSurface1* pSurface, QsFrameData& frameData);
void SetAspectRatio(VIDEOINFOHEADER2& vih2, mfxFrameInfo& FrameInfo);
mfxStatus ConvertFrameRate(mfxF64 dFrameRate, mfxU32& nFrameRateExtN, mfxU32& nFrameRateExtD);
mfxStatus OnVideoParamsChanged();
@ -93,7 +96,10 @@ protected:
inline void PushSurface(mfxFrameSurface1* pSurface);
inline mfxFrameSurface1* PopSurface();
void FlushOutputQueue(bool deliverFrames = true);
void AddBorders(mfxFrameSurface1* pSurface);
unsigned WorkerThreadMsgLoop();
// statics
static unsigned __stdcall WorkerThreadProc(void* pThis);
// data members
bool m_OK;
@ -105,15 +111,21 @@ protected:
mfxU32 m_nPitch;
CDecTimeManager m_TimeManager;
CFrameConstructor* m_pFrameConstructor;
unsigned char* m_OutputBuffer;
size_t m_OutputBufferSize;
size_t m_nSegmentFrameCount; // used for debugging mostly
volatile bool m_bFlushing; // like in DirectShow - current frame and data should be discarded
volatile bool m_bNeedToFlush;
volatile bool m_bNeedToFlush; // a flush was seen but not handled yet
bool m_bForceOutput;
bool m_bDvdDecoding;
bool m_bDvdDecoding; // support DVD decoding
CQsConfig m_Config;
HANDLE m_hWorkerThread;
unsigned m_WorkerThreadId;
volatile bool m_WorkerThreadIsRunning;
typedef std::pair<QsFrameData, CQsAlignedBuffer*> TQsQueueItem;
CQsThreadSafeQueue<TQsQueueItem> m_ProcessedFramesQueue; // after processing
CQsThreadSafeQueue<TQsQueueItem> m_FreeFramesPool;
// Output frame data
QsFrameData m_FrameData;
QsFrameData m_FrameDataTemplate;
};

View File

@ -62,7 +62,7 @@ CQuickSyncDecoder::CQuickSyncDecoder(mfxStatus& sts) :
m_pFrameAllocator(NULL),
m_pFrameSurfaces(NULL),
m_nRequiredFramesNum(0),
m_pRendererD2dDeviceManager(NULL),
m_pRendererD3dDeviceManager(NULL),
m_pD3dDeviceManager(NULL),
m_pD3dDevice(NULL)
{
@ -104,31 +104,23 @@ mfxFrameSurface1* CQuickSyncDecoder::FindFreeSurface()
MSDK_CHECK_POINTER(m_pFrameSurfaces, NULL);
//0.1 seconds cycle
for (int tries = 0; tries < 100; ++tries)
for (int tries = 0; tries < 1024; ++tries)
{
for (mfxU8 i = 0; i < m_nRequiredFramesNum; ++i)
{
if (0 == m_pFrameSurfaces[i].Data.Locked)
CQsAutoLock lock(&m_csLock);
for (mfxU8 i = 0; i < m_nRequiredFramesNum; ++i)
{
// find if surface is in output queue
bool bInQueue = false;
for (size_t j = 0; j < m_OutputSurfaceQueue.size(); ++j)
if (!IsSurfaceLocked(&m_pFrameSurfaces[i]))
{
if (m_OutputSurfaceQueue[j] == &m_pFrameSurfaces[i])
{
bInQueue = true;
break;
}
}
// found free surface :)
if (!bInQueue)
// found free surface :)
return &m_pFrameSurfaces[i];
}
}
}
MSDK_TRACE("QSDcoder: FindFreeSurface - all surfaces are in use, retrying in 1ms\n");
Sleep(1);
Sleep(tries+1);
}
return NULL;
@ -149,7 +141,7 @@ mfxStatus CQuickSyncDecoder::InitFrameAllocator(mfxVideoParam* pVideoParams, mfx
// Initialize frame allocator (if needed)
sts = CreateAllocator();
MSDK_CHECK_NOT_EQUAL(sts, MFX_ERR_NONE, sts);
// Find how many surfaces are needed
mfxFrameAllocRequest allocRequest;
MSDK_ZERO_VAR(allocRequest);
@ -467,7 +459,7 @@ mfxStatus CQuickSyncDecoder::CreateAllocator()
// Couldn't create our own device - probably a full screen exclusive player.
// We'll use the supplied renderer's device manager.
if (m_pRendererD2dDeviceManager)
if (m_pRendererD3dDeviceManager)
{
// Get DirectX Object
HANDLE hDevice;
@ -477,13 +469,13 @@ mfxStatus CQuickSyncDecoder::CreateAllocator()
D3DADAPTER_IDENTIFIER9 adIdentifier;
D3DPRESENT_PARAMETERS d3dParams = {1, 1, D3DFMT_X8R8G8B8, 1, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, NULL, TRUE, FALSE, D3DFMT_UNKNOWN, 0, 0, D3DPRESENT_INTERVAL_IMMEDIATE};
HRESULT hr = m_pRendererD2dDeviceManager->OpenDeviceHandle(&hDevice);
HRESULT hr = m_pRendererD3dDeviceManager->OpenDeviceHandle(&hDevice);
if (FAILED(hr))
{
MSDK_TRACE("QsDecoder: failed to open device handle!\n");
goto done;
}
hr = m_pRendererD2dDeviceManager->LockDevice(hDevice, &pDevice, TRUE);
hr = m_pRendererD3dDeviceManager->LockDevice(hDevice, &pDevice, TRUE);
if (FAILED(hr) && NULL == pDevice)
{
MSDK_TRACE("QsDecoder: failed to lock device!\n");
@ -514,7 +506,7 @@ mfxStatus CQuickSyncDecoder::CreateAllocator()
// If renderer is already on Intel's GPU than we can reuse the device.
if (adIdentifier.VendorId == 0x8086) //Intel's vendor ID is 8086h
{
m_pD3dDeviceManager = m_pRendererD2dDeviceManager;
m_pD3dDeviceManager = m_pRendererD3dDeviceManager;
goto done;
}
@ -574,10 +566,10 @@ done:
MSDK_SAFE_RELEASE(pDevice);
if (hDevice != NULL)
{
m_pRendererD2dDeviceManager->UnlockDevice(hDevice, FALSE);
m_pRendererD2dDeviceManager->CloseDeviceHandle(&hDevice);
m_pRendererD3dDeviceManager->UnlockDevice(hDevice, FALSE);
m_pRendererD3dDeviceManager->CloseDeviceHandle(&hDevice);
}
// m_pD3dDeviceManager = m_pRendererD2dDeviceManager;
// m_pD3dDeviceManager = m_pRendererD3dDeviceManager;
sts = MFX_ERR_NONE;
}
else
@ -643,9 +635,9 @@ mfxStatus CQuickSyncDecoder::UnlockFrame(mfxFrameSurface1* pSurface, mfxFrameDat
void CQuickSyncDecoder::SetD3DDeviceManager(IDirect3DDeviceManager9* pDeviceManager)
{
if (m_pRendererD2dDeviceManager == pDeviceManager)
if (m_pRendererD3dDeviceManager == pDeviceManager)
return;
MSDK_TRACE("QsDecoder: SetD3DDeviceManager called\n");
m_pRendererD2dDeviceManager = pDeviceManager;
m_pRendererD3dDeviceManager = pDeviceManager;
}

View File

@ -70,14 +70,33 @@ public:
mfxStatus DecodeHeader(mfxBitstream* bs, mfxVideoParam* par);
mfxStatus CheckHwAcceleration(mfxVideoParam* pVideoParams);
void SetConfig(const CQsConfig& cfg) { m_Config = cfg; }
TSurfaceQueue* GetOutputQueue() { return &m_OutputSurfaceQueue; }
__forceinline TSurfaceQueue& GetOutputQueue()
{
CQsAutoLock lock(&m_csLock);
return m_OutputSurfaceQueue;
}
__forceinline bool OutputQueueEmpty()
{
CQsAutoLock lock(&m_csLock);
return m_OutputSurfaceQueue.empty();
}
__forceinline size_t OutputQueueSize()
{
CQsAutoLock lock(&m_csLock);
return m_OutputSurfaceQueue.size();
}
__forceinline void PushSurface(mfxFrameSurface1* pSurface)
{
CQsAutoLock lock(&m_csLock);
m_OutputSurfaceQueue.push_back(pSurface);
}
__forceinline mfxFrameSurface1* PopSurface()
{
CQsAutoLock lock(&m_csLock);
if (m_OutputSurfaceQueue.empty())
return NULL;
@ -86,6 +105,42 @@ public:
return pSurface;
}
__forceinline void LockSurface(mfxFrameSurface1* pSurface)
{
CQsAutoLock lock(&m_csLock);
ASSERT(pSurface != NULL);
auto it = m_LockedSurfaces.find(pSurface);
if (it == m_LockedSurfaces.end())
{
m_LockedSurfaces.insert(pSurface);
}
}
__forceinline void UnlockSurface(mfxFrameSurface1* pSurface)
{
CQsAutoLock lock(&m_csLock);
ASSERT(pSurface != NULL);
auto it = m_LockedSurfaces.find(pSurface);
if (it != m_LockedSurfaces.end())
{
m_LockedSurfaces.erase(it);
}
}
bool IsSurfaceLocked(mfxFrameSurface1* pSurface)
{
CQsAutoLock lock(&m_csLock);
ASSERT(pSurface != NULL);
if (0 != pSurface->Data.Locked)
return true;
auto it = m_LockedSurfaces.find(pSurface);
return it != m_LockedSurfaces.end();
}
bool IsD3DAlloc() { return m_bUseD3DAlloc; }
bool IsHwAccelerated() { return m_bHwAcceleration; }
@ -118,12 +173,14 @@ protected:
bool m_bUseD3DAlloc;
// D3D/DXVA interfaces
IDirect3DDeviceManager9* m_pRendererD2dDeviceManager;
IDirect3DDeviceManager9* m_pRendererD3dDeviceManager;
IDirect3DDeviceManager9* m_pD3dDeviceManager;
IDirect3DDevice9* m_pD3dDevice;
TSurfaceQueue m_OutputSurfaceQueue;
std::set<mfxFrameSurface1*> m_LockedSurfaces;
CQsLock m_csLock;
private:
DISALLOW_COPY_AND_ASSIGN(CQuickSyncDecoder);

View File

@ -309,13 +309,6 @@ mfxStatus DARtoPAR(mfxU32 darw, mfxU32 darh, mfxU32 w, mfxU32 h, mfxU16& parw, m
return MFX_ERR_NONE;
}
void CopyBitstream(const mfxBitstream& src, mfxBitstream& trg)
{
memcpy(&trg, &src, sizeof(mfxBitstream));
trg.Data = new mfxU8[src.DataLength];
memcpy(trg.Data, src.Data, src.DataLength);
}
const char* GetCodecName(DWORD codec)
{
switch(codec)

View File

@ -28,44 +28,50 @@
#pragma once
// SSE4.1 based memcpy that copies from video memory to system memory
void* gpu_memcpy(void* d, const void* s, size_t _size);
// Finds greatest common divider
mfxU32 GCD(mfxU32 a, mfxU32 b);
// Pixel Aspect Ratio to Display Aspect Ratio conversion
mfxStatus PARtoDAR(DWORD parw, DWORD parh, DWORD w, DWORD h, DWORD& darw, DWORD& darh);
// Display Aspect Ratio to Pixel Aspect Ratio conversion
mfxStatus DARtoPAR(mfxU32 darw, mfxU32 darh, mfxU32 w, mfxU32 h, mfxU16& parw, mfxU16& parh);
void CopyBitstream(const mfxBitstream& src, mfxBitstream& trg);
// Name from codec identifier (MSDK enum)
const char* GetCodecName(DWORD codec);
// Name of codec's profile - profile identifier is accoding to DirectShow
const char* GetProfileName(DWORD codec, DWORD profile);
#ifdef _DEBUG
// Set current thread name in VS debugger
void SetThreadName(LPCSTR szThreadName, DWORD dwThreadID = -1 /* current thread */);
// Print assert to debugger output
void DebugAssert(const TCHAR *pCondition,const TCHAR *pFileName, int iLine);
#endif
// wrapper for whatever critical section we have
// Wrapper for low level critical section
class CQsLock
{
friend class CQsAutoLock;
friend class CQsAutoUnlock;
public:
CQsLock() { InitializeCriticalSection(&m_CritSec); }
~CQsLock() { DeleteCriticalSection(&m_CritSec); }
void Lock() { EnterCriticalSection(&m_CritSec); }
void Unlock() { LeaveCriticalSection(&m_CritSec); }
protected:
// make copy constructor and assignment operator inaccessible
private:
// Lock and Unlock are private nad can only be called from
// the CQsAutoLock/CQsAutoUnlock classes
__forceinline void Lock() { EnterCriticalSection(&m_CritSec); }
__forceinline void Unlock() { LeaveCriticalSection(&m_CritSec); }
// Make copy constructor and assignment operator inaccessible
DISALLOW_COPY_AND_ASSIGN(CQsLock)
// CQsLock(const CQsLock&);
// CQsLock& operator=(const CQsLock &);
CRITICAL_SECTION m_CritSec;
};
// locks a critical section, and unlocks it automatically
// when the lock goes out of scope
// Locks a critical section, and unlocks it automatically
// when the auto-lock object goes out of scope
class CQsAutoLock
{
protected:
CQsLock * m_pLock;
public:
CQsAutoLock(CQsLock* plock)
{
@ -80,7 +86,121 @@ public:
m_pLock->Unlock();
}
// make copy constructor and assignment operator inaccessible
CQsAutoLock(const CQsAutoLock &refAutoLock);
CQsAutoLock &operator=(const CQsAutoLock &refAutoLock);
private:
DISALLOW_COPY_AND_ASSIGN(CQsAutoLock);
CQsLock* m_pLock;
};
// Unlocks a critical section, and locks it automatically
// when the auto-unlock object goes out of scope
class CQsAutoUnlock
{
public:
CQsAutoUnlock(CQsLock* plock)
{
m_pLock = plock;
if (m_pLock != NULL)
m_pLock->Unlock();
}
~CQsAutoUnlock()
{
if (m_pLock != NULL)
m_pLock->Lock();
}
private:
DISALLOW_COPY_AND_ASSIGN(CQsAutoUnlock);
CQsLock* m_pLock;
};
// Thread safe queue template class
// Assumes a maximum capacity given by the user for
// the HasCapacity method to make sense.
template<class T> class CQsThreadSafeQueue : public CQsLock
{
public:
CQsThreadSafeQueue() : m_Capacity(0)
{
}
~CQsThreadSafeQueue()
{
// Better safe than sorry
CQsAutoLock lock(this);
}
__forceinline void Push(const T& item)
{
CQsAutoLock lock(this);
m_Queue.push_back(item);
m_Capacity = max(m_Queue.size(), m_Capacity);
}
__forceinline T Pop()
{
CQsAutoLock lock(this);
if (m_Queue.empty())
return T();
T res = m_Queue.front();
m_Queue.pop_front();
return res;
}
__forceinline size_t Size()
{
CQsAutoLock lock(this);
return m_Queue.size();
}
__forceinline void SetCapacity(size_t capacity)
{
CQsAutoLock lock(this);
m_Capacity = max(capacity, m_Capacity);
}
__forceinline size_t GetCapacity()
{
CQsAutoLock lock(this);
return m_Capacity;
}
__forceinline bool HasCapacity()
{
CQsAutoLock lock(this);
return m_Queue.size() < m_Capacity;
}
__forceinline bool Empty()
{
CQsAutoLock lock(this);
return m_Queue.empty();
}
private:
std::deque<T> m_Queue;
size_t m_Capacity;
};
// Simple SSE friendly buffer class
class CQsAlignedBuffer
{
public:
CQsAlignedBuffer(size_t bufferSize) : m_BufferSize(bufferSize)
{
m_Buffer = (BYTE*)_aligned_malloc(m_BufferSize, 16);
}
~CQsAlignedBuffer()
{
_aligned_free(m_Buffer);
}
__forceinline size_t GetBufferSize() { return m_BufferSize; }
__forceinline BYTE* GetBuffer() { return m_Buffer; }
private:
size_t m_BufferSize;
BYTE* m_Buffer;
};

View File

@ -78,8 +78,15 @@
_snprintf_s(msg, MSDK_ARRAY_LEN(msg), MSDK_ARRAY_LEN(msg) - 1, _format, __VA_ARGS__); \
OutputDebugStringA(msg); \
}
// MSDK_VTRACE should be used for very frequent prints
# ifdef VERBOSE
# define MSDK_VTRACE MSDK_TRACE
# else
# define MSDK_VTRACE
# endif
#else
# define MSDK_TRACE(_format, ...)
# define MSDK_VTRACE(_format, ...)
#endif
// A macro to disallow the copy constructor and operator= functions

View File

@ -43,7 +43,6 @@ void CDecTimeManager::Reset()
{
m_nOutputFrames = -1;
m_nSegmentSampleCount = 0;
m_TimeStampQueue.clear();
m_OutputTimeStamps.clear();
m_bValidFrameRate = false;
m_nLastSeenFieldDoubling = 0;
@ -52,19 +51,6 @@ void CDecTimeManager::Reset()
SetInverseTelecine(false);
}
void CDecTimeManager::AddTimeStamp(IMediaSample* pSample)
{
REFERENCE_TIME rtStart, rtStop;
HRESULT hr = pSample->GetTime(&rtStart, &rtStop);
if (S_OK != hr && VFW_S_NO_STOP_TIME != hr)
{
rtStart = INVALID_REFTIME;
}
PushTimeStamp(m_nSegmentSampleCount++, rtStart);
}
bool CDecTimeManager::CalcFrameRate(const mfxFrameSurface1* pSurface,
const std::deque<mfxFrameSurface1*>& queue)
{
@ -188,16 +174,6 @@ void CDecTimeManager::SetInverseTelecine(bool bIvtc)
}
}
REFERENCE_TIME CDecTimeManager::PopTimeStamp()
{
if (m_TimeStampQueue.empty())
return INVALID_REFTIME;
TTimeStampInfo tsInfo = m_TimeStampQueue.front();
m_TimeStampQueue.pop_front();
return tsInfo.rtStart;
}
bool CDecTimeManager::GetSampleTimeStamp(const mfxFrameSurface1* pSurface,
const std::deque<mfxFrameSurface1*>& queue,
REFERENCE_TIME& rtStart,
@ -227,8 +203,6 @@ bool CDecTimeManager::GetSampleTimeStamp(const mfxFrameSurface1* pSurface,
}
++m_nOutputFrames;
if (m_TimeStampQueue.size() > 100)
PopTimeStamp();
// Can't start the sequence - drop frame
if (rtDecoder == INVALID_REFTIME && m_rtPrevStart == INVALID_REFTIME)

View File

@ -91,7 +91,6 @@ public:
return (REFERENCE_TIME)(((double)t / (double)MFX_TIME_STAMP_FREQUENCY) * 1e7);
}
void AddTimeStamp(IMediaSample* pSample);
void AddOutputTimeStamp(mfxFrameSurface1* pSurface);
bool CalcFrameRate(const mfxFrameSurface1* pSurface,
const std::deque<mfxFrameSurface1*>& queue);
@ -106,19 +105,9 @@ public:
static const double fps23976;
protected:
inline void PushTimeStamp(int id, REFERENCE_TIME rtStart)
{
#ifdef _DEBUG
TTimeStampInfo t(id, rtStart);
m_TimeStampQueue.push_back(t);
#endif
}
REFERENCE_TIME PopTimeStamp();
void FixFrameRate(double frameRate);
bool CalcCurrentFrameRate(double& tmpFrameRate, size_t nQueuedFrames);
// double m_dDecodeTime;
double m_dOrigFrameRate;
double m_dFrameRate;
bool m_bValidFrameRate;
@ -130,6 +119,5 @@ protected:
bool m_bIsSampleInFields;
bool m_bEnableIvtc;
REFERENCE_TIME m_rtPrevStart;
TTimeStampQueue m_TimeStampQueue;
TSortedTimeStamps m_OutputTimeStamps;
};

16
resource.h Normal file
View File

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by IntelQuickSyncDecoder.rc
//
#define VS_VERSION_INFO 1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif