git-svn-id: svn://svn.code.sf.net/p/qsdecoder/code/trunk/IntelQuickSyncDecoder@9 dfccccb7-dd81-40b7-a334-5a7ba89c2b1d
This commit is contained in:
parent
e1c96fc123
commit
f69a0e60a7
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
582
QuickSync.cpp
582
QuickSync.cpp
|
@ -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;
|
||||
}
|
||||
|
|
28
QuickSync.h
28
QuickSync.h
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
154
QuickSyncUtils.h
154
QuickSyncUtils.h
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue