This commit is contained in:
mofeng-git
2025-12-28 18:19:16 +08:00
commit d143d158e4
771 changed files with 220548 additions and 0 deletions

View File

@@ -0,0 +1,721 @@
//
// Notice Regarding Standards. AMD does not provide a license or sublicense to
// any Intellectual Property Rights relating to any standards, including but not
// limited to any audio and/or video codec technologies such as MPEG-2, MPEG-4;
// AVC/H.264; HEVC/H.265; AAC decode/FFMPEG; AAC encode/FFMPEG; VC-1; and MP3
// (collectively, the "Media Technologies"). For clarity, you will pay any
// royalties due for such third party technologies, which may include the Media
// Technologies that are owed as a result of AMD providing the Software to you.
//
// MIT license
//
// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#ifndef AMF_Thread_h
#define AMF_Thread_h
#pragma once
#include <cassert>
#include <list>
#include <vector>
#include "../include/core/Platform.h"
#ifndef _WIN32
#include <pthread.h>
#endif
extern "C"
{
// threads
#define AMF_INFINITE (0xFFFFFFFF) // Infinite ulTimeout
// threads: atomic
amf_long AMF_CDECL_CALL amf_atomic_inc(amf_long* X);
amf_long AMF_CDECL_CALL amf_atomic_dec(amf_long* X);
// threads: critical section
amf_handle AMF_CDECL_CALL amf_create_critical_section();
bool AMF_CDECL_CALL amf_delete_critical_section(amf_handle cs);
bool AMF_CDECL_CALL amf_enter_critical_section(amf_handle cs);
bool AMF_CDECL_CALL amf_wait_critical_section(amf_handle cs, amf_ulong ulTimeout);
bool AMF_CDECL_CALL amf_leave_critical_section(amf_handle cs);
// threads: event
amf_handle AMF_CDECL_CALL amf_create_event(bool bInitiallyOwned, bool bManualReset, const wchar_t* pName);
bool AMF_CDECL_CALL amf_delete_event(amf_handle hevent);
bool AMF_CDECL_CALL amf_set_event(amf_handle hevent);
bool AMF_CDECL_CALL amf_reset_event(amf_handle hevent);
bool AMF_CDECL_CALL amf_wait_for_event(amf_handle hevent, amf_ulong ulTimeout);
bool AMF_CDECL_CALL amf_wait_for_event_timeout(amf_handle hevent, amf_ulong ulTimeout);
// threads: mutex
amf_handle AMF_CDECL_CALL amf_create_mutex(bool bInitiallyOwned, const wchar_t* pName);
#if defined(_WIN32)
amf_handle AMF_CDECL_CALL amf_open_mutex(const wchar_t* pName);
#endif
bool AMF_CDECL_CALL amf_delete_mutex(amf_handle hmutex);
bool AMF_CDECL_CALL amf_wait_for_mutex(amf_handle hmutex, amf_ulong ulTimeout);
bool AMF_CDECL_CALL amf_release_mutex(amf_handle hmutex);
// threads: semaphore
amf_handle AMF_CDECL_CALL amf_create_semaphore(amf_long iInitCount, amf_long iMaxCount, const wchar_t* pName);
bool AMF_CDECL_CALL amf_delete_semaphore(amf_handle hsemaphore);
bool AMF_CDECL_CALL amf_wait_for_semaphore(amf_handle hsemaphore, amf_ulong ulTimeout);
bool AMF_CDECL_CALL amf_release_semaphore(amf_handle hsemaphore, amf_long iCount, amf_long* iOldCount);
// threads: delay
void AMF_CDECL_CALL amf_sleep(amf_ulong delay);
amf_pts AMF_CDECL_CALL amf_high_precision_clock(); // in 100 of nanosec
void AMF_CDECL_CALL amf_increase_timer_precision();
void AMF_CDECL_CALL amf_restore_timer_precision();
amf_handle AMF_CDECL_CALL amf_load_library(const wchar_t* filename);
amf_handle AMF_CDECL_CALL amf_load_library1(const wchar_t* filename, bool bGlobal);
void* AMF_CDECL_CALL amf_get_proc_address(amf_handle module, const char* procName);
int AMF_CDECL_CALL amf_free_library(amf_handle module);
#if defined(__APPLE__)
amf_uint64 AMF_STD_CALL get_current_thread_id();
#else
amf_uint32 AMF_STD_CALL get_current_thread_id();
#endif
#if !defined(METRO_APP)
// virtual memory
void* AMF_CDECL_CALL amf_virtual_alloc(amf_size size);
void AMF_CDECL_CALL amf_virtual_free(void* ptr);
#else
#define amf_virtual_alloc amf_alloc
#define amf_virtual_free amf_free
#endif
// cpu
#if defined(_WIN32) || (__linux__)
amf_int32 AMF_STD_CALL amf_get_cpu_cores();
#endif
}
namespace amf
{
//----------------------------------------------------------------
class AMF_NO_VTABLE AMFSyncBase
{
public:
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE) = 0;
virtual bool Unlock() = 0;
};
//----------------------------------------------------------------
class AMFEvent : public AMFSyncBase
{
private:
amf_handle m_hSyncObject;
AMFEvent(const AMFEvent&);
AMFEvent& operator=(const AMFEvent&);
public:
AMFEvent(bool bInitiallyOwned = false, bool bManualReset = false, const wchar_t* pName = NULL);
virtual ~AMFEvent();
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE);
virtual bool LockTimeout(amf_ulong ulTimeout = AMF_INFINITE);
virtual bool Unlock();
bool SetEvent();
bool ResetEvent();
amf_handle GetNative() { return m_hSyncObject; }
};
//----------------------------------------------------------------
class AMFMutex : public AMFSyncBase
{
private:
amf_handle m_hSyncObject;
AMFMutex(const AMFMutex&);
AMFMutex& operator=(const AMFMutex&);
public:
AMFMutex(bool bInitiallyOwned = false, const wchar_t* pName = NULL
#if defined(_WIN32)
, bool bOpenExistent = false
#endif
);
virtual ~AMFMutex();
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE);
virtual bool Unlock();
bool IsValid();
};
//----------------------------------------------------------------
class AMFCriticalSection : public AMFSyncBase
{
private:
amf_handle m_Sect;
AMFCriticalSection(const AMFCriticalSection&);
AMFCriticalSection& operator=(const AMFCriticalSection&);
public:
AMFCriticalSection();
virtual ~AMFCriticalSection();
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE);
virtual bool Unlock();
};
//----------------------------------------------------------------
class AMFSemaphore : public AMFSyncBase
{
private:
amf_handle m_hSemaphore;
AMFSemaphore(const AMFSemaphore&);
AMFSemaphore& operator=(const AMFSemaphore&);
public:
AMFSemaphore(amf_long iInitCount, amf_long iMaxCount, const wchar_t* pName = NULL);
virtual ~AMFSemaphore();
virtual bool Create(amf_long iInitCount, amf_long iMaxCount, const wchar_t* pName = NULL);
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE);
virtual bool Unlock();
};
//----------------------------------------------------------------
class AMFLock
{
private:
AMFSyncBase* m_pBase;
bool m_bLocked;
AMFLock(const AMFLock&);
AMFLock& operator=(const AMFLock&);
public:
AMFLock(AMFSyncBase* pBase, amf_ulong ulTimeout = AMF_INFINITE);
~AMFLock();
bool Lock(amf_ulong ulTimeout = AMF_INFINITE);
bool Unlock();
bool IsLocked();
};
//----------------------------------------------------------------
class AMFReadWriteSync
{
private:
struct ReadWriteResources
{
// max threads reading concurrently
const int m_maxReadThreads;
AMFSemaphore m_readSemaphore;
AMFCriticalSection m_writeCriticalSection;
ReadWriteResources() :
m_maxReadThreads(10),
m_readSemaphore(m_maxReadThreads, m_maxReadThreads),
m_writeCriticalSection()
{ }
};
class ReadSync : public AMFSyncBase
{
private:
ReadSync(const ReadSync&);
ReadSync& operator=(const ReadSync&);
ReadWriteResources& m_resources;
public:
ReadSync(ReadWriteResources& resources) : m_resources(resources)
{ }
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE)
{
return m_resources.m_readSemaphore.Lock(ulTimeout);
}
virtual bool Unlock()
{
return m_resources.m_readSemaphore.Unlock();
}
};
class WriteSync : public AMFSyncBase
{
private:
WriteSync(const WriteSync&);
WriteSync& operator=(const WriteSync&);
ReadWriteResources& m_resources;
public:
WriteSync(ReadWriteResources& resources) : m_resources(resources)
{ }
/// waits passed timeout for other writers; wait readers for infinite
virtual bool Lock(amf_ulong ulTimeout = AMF_INFINITE)
{
if(!m_resources.m_writeCriticalSection.Lock(ulTimeout))
{
return false;
}
for(int i = 0; i < m_resources.m_maxReadThreads; i++)
{
m_resources.m_readSemaphore.Lock();
}
return true;
}
virtual bool Unlock()
{
// there is windows function to release N times by one call - could be optimize later
for(int i = 0; i < m_resources.m_maxReadThreads; i++)
{
m_resources.m_readSemaphore.Unlock();
}
return m_resources.m_writeCriticalSection.Unlock();
}
};
private:
ReadWriteResources m_resources;
ReadSync m_readSync;
WriteSync m_writeSync;
public:
AMFReadWriteSync() :
m_resources(),
m_readSync(m_resources),
m_writeSync(m_resources)
{ }
AMFSyncBase* GetReadSync()
{
return &m_readSync;
}
AMFSyncBase* GetWriteSync()
{
return &m_writeSync;
}
};
//----------------------------------------------------------------
class AMFThreadObj;
class AMFThread
{
friend class AMFThreadObj;
public:
AMFThread();
virtual ~AMFThread();
virtual bool Start();
virtual bool RequestStop();
virtual bool WaitForStop();
virtual bool StopRequested();
virtual bool IsRunning() const;
protected:
// this is executed in the thread and overloaded by implementor
virtual void Run() = 0;
virtual bool Init()
{
return true;
}
virtual bool Terminate()
{
return true;
}
private:
AMFThreadObj* m_thread;
AMFThread(const AMFThread&);
AMFThread& operator=(const AMFThread&);
};
void ExitThread();
//----------------------------------------------------------------
template<typename T>
class AMFQueue
{
protected:
class ItemData
{
public:
T data;
amf_ulong ulID;
amf_long ulPriority;
ItemData() : data(), ulID(), ulPriority(){}
};
typedef std::list< ItemData > QueueList;
QueueList m_Queue;
AMFCriticalSection m_cSect;
AMFEvent m_SomethingInQueueEvent;
AMFSemaphore m_QueueSizeSem;
amf_int32 m_iQueueSize;
bool InternalGet(amf_ulong& ulID, T& item)
{
AMFLock lock(&m_cSect);
if(!m_Queue.empty()) // something to get
{
ItemData& itemdata = m_Queue.front();
ulID = itemdata.ulID;
item = itemdata.data;
m_Queue.pop_front();
m_QueueSizeSem.Unlock();
if(m_Queue.empty())
{
m_SomethingInQueueEvent.ResetEvent();
}
return true;
}
return false;
}
public:
AMFQueue(amf_int32 iQueueSize = 0)
: m_Queue(),
m_cSect(),
m_SomethingInQueueEvent(false, false),
m_QueueSizeSem(iQueueSize, iQueueSize > 0 ? iQueueSize + 1 : 0),
m_iQueueSize(iQueueSize) {}
virtual ~AMFQueue(){}
virtual bool SetQueueSize(amf_int32 iQueueSize)
{
bool success = m_QueueSizeSem.Create(iQueueSize, iQueueSize > 0 ? iQueueSize + 1 : 0);
if(success)
{
m_iQueueSize = iQueueSize;
}
return success;
}
virtual amf_int32 GetQueueSize()
{
return m_iQueueSize;
}
virtual bool Add(amf_ulong ulID, const T& item, amf_long ulPriority = 0, amf_ulong ulTimeout = AMF_INFINITE)
{
if(m_QueueSizeSem.Lock(ulTimeout) == false)
{
return false;
}
{
AMFLock lock(&m_cSect);
ItemData itemdata;
itemdata.ulID = ulID;
itemdata.data = item;
itemdata.ulPriority = ulPriority;
typename QueueList::iterator iter = m_Queue.end();
for(; iter != m_Queue.begin(); )
{
iter--;
if(ulPriority <= (iter->ulPriority))
{
iter++;
break;
}
}
m_Queue.insert(iter, itemdata);
m_SomethingInQueueEvent.SetEvent(); // this will set all waiting threads - some of them get data, some of them not
}
return true;
}
virtual bool Get(amf_ulong& ulID, T& item, amf_ulong ulTimeout)
{
if(InternalGet(ulID, item)) // try right away
{
return true;
}
// wait for queue
if(m_SomethingInQueueEvent.Lock(ulTimeout))
{
return InternalGet(ulID, item);
}
return false;
}
virtual void Clear()
{
bool bValue = true;
while(bValue)
{
amf_ulong ulID;
T item;
bValue = InternalGet(ulID, item);
}
}
virtual amf_size GetSize()
{
AMFLock lock(&m_cSect);
return m_Queue.size();
}
};
//----------------------------------------------------------------
template<class inT, class outT>
class AMFQueueThread : public AMFThread
{
private:
AMFQueueThread(const AMFQueueThread&);
AMFQueueThread& operator=(const AMFQueueThread&);
protected:
AMFQueue<inT>* m_pInQueue;
AMFQueue<outT>* m_pOutQueue;
AMFMutex m_mutexInProcess; ///< This mutex shows other threads that the thread function allocates
///< some objects on stack and it is unsafe state. To manipulate objects owned by descendant classes
///< client must lock this mutex by calling BlockProcessing member function. When client finished its work
///< corresponding UnblockProcessing member function call must be done.
bool m_blockProcessingRequested;
AMFCriticalSection m_csBlockingRequest;
public:
AMFQueueThread(AMFQueue<inT>* pInQueue,
AMFQueue<outT>* pOutQueue) : m_pInQueue(pInQueue), m_pOutQueue(pOutQueue), m_mutexInProcess(),
m_blockProcessingRequested(false), m_csBlockingRequest()
{}
virtual bool Process(amf_ulong& ulID, inT& inData, outT& outData) = 0;
virtual void BlockProcessing()
{
AMFLock lock(&m_csBlockingRequest);
m_blockProcessingRequested = true;
m_mutexInProcess.Lock();
}
virtual void UnblockProcessing()
{
AMFLock lock(&m_csBlockingRequest);
m_mutexInProcess.Unlock();
m_blockProcessingRequested = false;
}
virtual bool IsPaused()
{
return false;
}
virtual void OnHaveOutput() {}
virtual void OnIdle() {}
virtual void Run()
{
bool bStop = false;
while(!bStop)
{
{
AMFLock lock(&m_mutexInProcess);
inT inData;
amf_ulong ulID = 0;
bool callProcess = true;
if(m_pInQueue != NULL)
{
amf_ulong waitTimeout = 5;
bool validInput = m_pInQueue->Get(ulID, inData, waitTimeout); // Pulse to check Stop from time to time
if(StopRequested())
{
bStop = true;
}
if(!validInput)
{
callProcess = false;
}
}
if(!bStop && callProcess)
{
outT outData;
bool validOutput = Process(ulID, inData, outData);
if(StopRequested())
{
bStop = true;
}
if(!bStop && (m_pOutQueue != NULL) && validOutput)
{
m_pOutQueue->Add(ulID, outData);
OnHaveOutput();
}
}
else
{
OnIdle();
}
}
if(StopRequested())
{
bStop = true;
}
#if defined(__linux) || defined(__APPLE__)
///< HACK
///< This amf_sleep(0) is required to emulate windows mutex behavior.
///< In Windows release mutext causes some other waiting thread is receiving ownership of mutex.
///< In Linux it is not true.
///< Without sleep AMFLock destructor releases mutex but immediately on next cycle AMFLock constructor tries to lock
///< the mutex and now system have two threads waiting for the mutex.
///< Using some random logic system decides who will be unlocked.
///< This thread may win during several seconds it looks like pipeline is hang.
///< amf_sleep call causes waiting thread is becoming unlocked.
if(m_blockProcessingRequested)
{
amf_sleep(0);
}
#endif
}
}
};
//----------------------------------------------------------------
template<class inT, class outT, class _Thread, class ThreadParam>
class AMFQueueThreadPipeline
{
private:
AMFQueueThreadPipeline(const AMFQueueThreadPipeline&);
AMFQueueThreadPipeline& operator=(const AMFQueueThreadPipeline&);
public:
AMFQueue<inT>* m_pInQueue;
AMFQueue<outT>* m_pOutQueue;
std::vector<_Thread*> m_ThreadPool;
AMFQueueThreadPipeline(AMFQueue<inT>* pInQueue, AMFQueue<outT>* pOutQueue)
: m_pInQueue(pInQueue),
m_pOutQueue(pOutQueue),
m_ThreadPool()
{}
virtual ~AMFQueueThreadPipeline()
{
Stop();
}
void Start(int iNumberOfThreads, ThreadParam param)
{
if((long)m_ThreadPool.size() >= iNumberOfThreads)
{
Stop(); //temporary to remove stopped threads. need callback from thread to clean pool
//return;
}
size_t initialSize = m_ThreadPool.size();
for(size_t i = initialSize; i < (size_t)iNumberOfThreads; i++)
{
_Thread* pThread = new _Thread(m_pInQueue, m_pOutQueue, param);
m_ThreadPool.push_back(pThread);
pThread->Start();
}
}
void RequestStop()
{
long num = (long)m_ThreadPool.size();
for(long i = 0; i < num; i++)
{
m_ThreadPool[i]->RequestStop();
}
}
void BlockProcessing()
{
long num = (long)m_ThreadPool.size();
for(long i = 0; i < num; i++)
{
m_ThreadPool[i]->BlockProcessing();
}
}
void UnblockProcessing()
{
long num = (long)m_ThreadPool.size();
for(long i = 0; i < num; i++)
{
m_ThreadPool[i]->UnblockProcessing();
}
}
void WaitForStop()
{
long num = (long)m_ThreadPool.size();
for(long i = 0; i < num; i++)
{
_Thread* pThread = m_ThreadPool[i];
pThread->WaitForStop();
delete pThread;
}
m_ThreadPool.clear();
}
void Stop()
{
RequestStop();
WaitForStop();
}
};
//----------------------------------------------------------------
class AMFPreciseWaiter
{
public:
AMFPreciseWaiter() : m_WaitEvent(), m_bCancel(false)
{}
virtual ~AMFPreciseWaiter()
{}
amf_pts Wait(amf_pts waittime)
{
if (waittime < 0)
{
return 0;
}
m_bCancel = false;
amf_pts start = amf_high_precision_clock();
amf_pts waited = 0;
int count = 0;
while(!m_bCancel)
{
count++;
if(!m_WaitEvent.LockTimeout(1))
{
break;
}
waited = amf_high_precision_clock() - start;
if(waited >= waittime)
{
break;
}
}
return waited;
}
amf_pts WaitEx(amf_pts waittime)
{
m_bCancel = false;
amf_pts start = amf_high_precision_clock();
amf_pts waited = 0;
int count = 0;
while (!m_bCancel && waited < waittime)
{
if (waittime - waited < 2 * AMF_SECOND / 1000)// last 2 ms burn CPU for precision
{
for (int i = 0; i < 1000; i++)
{
count++;
#ifdef _WIN32
YieldProcessor();
#endif
}
}
else if (!m_WaitEvent.LockTimeout(1))
{
break;
}
waited = amf_high_precision_clock() - start;
}
return waited;
}
void Cancel()
{
m_bCancel = true;
}
protected:
AMFEvent m_WaitEvent;
bool m_bCancel;
};
//----------------------------------------------------------------
} // namespace amf
#endif // AMF_Thread_h