feat: 切换后端至PaddleOCR-NCNN,切换工程为CMake

1.项目后端整体迁移至PaddleOCR-NCNN算法,已通过基本的兼容性测试
2.工程改为使用CMake组织,后续为了更好地兼容第三方库,不再提供QMake工程
3.重整权利声明文件,重整代码工程,确保最小化侵权风险

Log: 切换后端至PaddleOCR-NCNN,切换工程为CMake
Change-Id: I4d5d2c5d37505a4a24b389b1a4c5d12f17bfa38c
This commit is contained in:
wangzhengyang
2022-05-10 09:54:44 +08:00
parent ecdd171c6f
commit 718c41634f
10018 changed files with 3593797 additions and 186748 deletions

View File

@ -0,0 +1,81 @@
#pragma once
//////////////////////////////////////////////////////////////////////////
// AsyncCallback [template]
//
// Description:
// Helper class that routes IMFAsyncCallback::Invoke calls to a class
// method on the parent class.
//
// Usage:
// Add this class as a member variable. In the parent class constructor,
// initialize the AsyncCallback class like this:
// m_cb(this, &CYourClass::OnInvoke)
// where
// m_cb = AsyncCallback object
// CYourClass = parent class
// OnInvoke = Method in the parent class to receive Invoke calls.
//
// The parent's OnInvoke method (you can name it anything you like) must
// have a signature that matches the InvokeFn typedef below.
//////////////////////////////////////////////////////////////////////////
// T: Type of the parent object
template<class T>
class AsyncCallback : public IMFAsyncCallback
{
public:
typedef HRESULT (T::*InvokeFn)(IMFAsyncResult *pAsyncResult);
AsyncCallback(T *pParent, InvokeFn fn) : m_pParent(pParent), m_pInvokeFn(fn)
{
}
// IUnknown
STDMETHODIMP_(ULONG) AddRef() {
// Delegate to parent class.
return m_pParent->AddRef();
}
STDMETHODIMP_(ULONG) Release() {
// Delegate to parent class.
return m_pParent->Release();
}
STDMETHODIMP QueryInterface(REFIID iid, void** ppv)
{
if (!ppv)
{
return E_POINTER;
}
if (iid == __uuidof(IUnknown))
{
*ppv = static_cast<IUnknown*>(static_cast<IMFAsyncCallback*>(this));
}
else if (iid == __uuidof(IMFAsyncCallback))
{
*ppv = static_cast<IMFAsyncCallback*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// IMFAsyncCallback methods
STDMETHODIMP GetParameters(DWORD*, DWORD*)
{
// Implementation of this method is optional.
return E_NOTIMPL;
}
STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
{
return (m_pParent->*m_pInvokeFn)(pAsyncResult);
}
T *m_pParent;
InvokeFn m_pInvokeFn;
};

View File

@ -0,0 +1,101 @@
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#pragma once
//////////////////////////////////////////////////////////////////////////
// VideoBufferLock
//
// Description:
// Locks a video buffer that might or might not support IMF2DBuffer.
//
//////////////////////////////////////////////////////////////////////////
class VideoBufferLock
{
public:
VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL)
{
m_pBuffer = pBuffer;
m_pBuffer->AddRef();
// Query for the 2-D buffer interface. OK if this fails.
m_pBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer));
}
~VideoBufferLock()
{
UnlockBuffer();
SafeRelease(&m_pBuffer);
SafeRelease(&m_p2DBuffer);
}
// LockBuffer:
// Locks the buffer. Returns a pointer to scan line 0 and returns the stride.
// The caller must provide the default stride as an input parameter, in case
// the buffer does not expose IMF2DBuffer. You can calculate the default stride
// from the media type.
HRESULT LockBuffer(
LONG lDefaultStride, // Minimum stride (with no padding).
DWORD dwHeightInPixels, // Height of the image, in pixels.
BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0.
LONG *plStride // Receives the actual stride.
)
{
HRESULT hr = S_OK;
// Use the 2-D version if available.
if (m_p2DBuffer)
{
hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride);
}
else
{
// Use non-2D version.
BYTE *pData = NULL;
hr = m_pBuffer->Lock(&pData, NULL, NULL);
if (SUCCEEDED(hr))
{
*plStride = lDefaultStride;
if (lDefaultStride < 0)
{
// Bottom-up orientation. Return a pointer to the start of the
// last row *in memory* which is the top row of the image.
*ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1);
}
else
{
// Top-down orientation. Return a pointer to the start of the
// buffer.
*ppbScanLine0 = pData;
}
}
}
return hr;
}
HRESULT UnlockBuffer()
{
if (m_p2DBuffer)
{
return m_p2DBuffer->Unlock2D();
}
else
{
return m_pBuffer->Unlock();
}
}
private:
IMFMediaBuffer *m_pBuffer;
IMF2DBuffer *m_p2DBuffer;
};

View File

@ -0,0 +1,62 @@
#pragma once
//////////////////////////////////////////////////////////////////////////
// CritSec
// Description: Wraps a critical section.
//////////////////////////////////////////////////////////////////////////
class CritSec
{
public:
CRITICAL_SECTION m_criticalSection;
public:
CritSec()
{
InitializeCriticalSectionEx(&m_criticalSection, 100, 0);
}
~CritSec()
{
DeleteCriticalSection(&m_criticalSection);
}
_Acquires_lock_(m_criticalSection)
void Lock()
{
EnterCriticalSection(&m_criticalSection);
}
_Releases_lock_(m_criticalSection)
void Unlock()
{
LeaveCriticalSection(&m_criticalSection);
}
};
//////////////////////////////////////////////////////////////////////////
// AutoLock
// Description: Provides automatic locking and unlocking of a
// of a critical section.
//
// Note: The AutoLock object must go out of scope before the CritSec.
//////////////////////////////////////////////////////////////////////////
class AutoLock
{
private:
CritSec *m_pCriticalSection;
public:
_Acquires_lock_(m_pCriticalSection)
AutoLock(CritSec& crit)
{
m_pCriticalSection = &crit;
m_pCriticalSection->Lock();
}
_Releases_lock_(m_pCriticalSection)
~AutoLock()
{
m_pCriticalSection->Unlock();
}
};

View File

@ -0,0 +1,516 @@
//-----------------------------------------------------------------------------
// File: Linklist.h
// Desc: Linked list class.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#pragma once
// Notes:
//
// The List class template implements a simple double-linked list.
// It uses STL's copy semantics.
// There are two versions of the Clear() method:
// Clear(void) clears the list w/out cleaning up the object.
// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup.
// The List class supports enumeration. Example of usage:
//
// List<T>::POSIITON pos = list.GetFrontPosition();
// while (pos != list.GetEndPosition())
// {
// T item;
// hr = list.GetItemPos(&item);
// pos = list.Next(pos);
// }
// The ComPtrList class template derives from List<> and implements a list of COM pointers.
template <class T>
struct NoOp
{
void operator()(T& t)
{
}
};
template <class T>
class List
{
protected:
// Nodes in the linked list
struct Node
{
Node *prev;
Node *next;
T item;
Node() : prev(nullptr), next(nullptr)
{
}
Node(T item) : prev(nullptr), next(nullptr)
{
this->item = item;
}
T Item() const { return item; }
};
public:
// Object for enumerating the list.
class POSITION
{
friend class List<T>;
public:
POSITION() : pNode(nullptr)
{
}
bool operator==(const POSITION &p) const
{
return pNode == p.pNode;
}
bool operator!=(const POSITION &p) const
{
return pNode != p.pNode;
}
private:
const Node *pNode;
POSITION(Node *p) : pNode(p)
{
}
};
protected:
Node m_anchor; // Anchor node for the linked list.
DWORD m_count; // Number of items in the list.
Node* Front() const
{
return m_anchor.next;
}
Node* Back() const
{
return m_anchor.prev;
}
virtual HRESULT InsertAfter(T item, Node *pBefore)
{
if (pBefore == nullptr)
{
return E_POINTER;
}
Node *pNode = new Node(item);
if (pNode == nullptr)
{
return E_OUTOFMEMORY;
}
Node *pAfter = pBefore->next;
pBefore->next = pNode;
pAfter->prev = pNode;
pNode->prev = pBefore;
pNode->next = pAfter;
m_count++;
return S_OK;
}
virtual HRESULT GetItem(const Node *pNode, T* ppItem)
{
if (pNode == nullptr || ppItem == nullptr)
{
return E_POINTER;
}
*ppItem = pNode->item;
return S_OK;
}
// RemoveItem:
// Removes a node and optionally returns the item.
// ppItem can be nullptr.
virtual HRESULT RemoveItem(Node *pNode, T *ppItem)
{
if (pNode == nullptr)
{
return E_POINTER;
}
assert(pNode != &m_anchor); // We should never try to remove the anchor node.
if (pNode == &m_anchor)
{
return E_INVALIDARG;
}
T item;
// The next node's previous is this node's previous.
pNode->next->prev = pNode->prev;
// The previous node's next is this node's next.
pNode->prev->next = pNode->next;
item = pNode->item;
delete pNode;
m_count--;
if (ppItem)
{
*ppItem = item;
}
return S_OK;
}
public:
List()
{
m_anchor.next = &m_anchor;
m_anchor.prev = &m_anchor;
m_count = 0;
}
virtual ~List()
{
Clear();
}
// Insertion functions
HRESULT InsertBack(T item)
{
return InsertAfter(item, m_anchor.prev);
}
HRESULT InsertFront(T item)
{
return InsertAfter(item, &m_anchor);
}
HRESULT InsertPos(POSITION pos, T item)
{
if (pos.pNode == nullptr)
{
return InsertBack(item);
}
return InsertAfter(item, pos.pNode->prev);
}
// RemoveBack: Removes the tail of the list and returns the value.
// ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
HRESULT RemoveBack(T *ppItem)
{
if (IsEmpty())
{
return E_FAIL;
}
else
{
return RemoveItem(Back(), ppItem);
}
}
// RemoveFront: Removes the head of the list and returns the value.
// ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)
HRESULT RemoveFront(T *ppItem)
{
if (IsEmpty())
{
return E_FAIL;
}
else
{
return RemoveItem(Front(), ppItem);
}
}
// GetBack: Gets the tail item.
HRESULT GetBack(T *ppItem)
{
if (IsEmpty())
{
return E_FAIL;
}
else
{
return GetItem(Back(), ppItem);
}
}
// GetFront: Gets the front item.
HRESULT GetFront(T *ppItem)
{
if (IsEmpty())
{
return E_FAIL;
}
else
{
return GetItem(Front(), ppItem);
}
}
// GetCount: Returns the number of items in the list.
DWORD GetCount() const { return m_count; }
bool IsEmpty() const
{
return (GetCount() == 0);
}
// Clear: Takes a functor object whose operator()
// frees the object on the list.
template <class FN>
void Clear(FN& clear_fn)
{
Node *n = m_anchor.next;
// Delete the nodes
while (n != &m_anchor)
{
clear_fn(n->item);
Node *tmp = n->next;
delete n;
n = tmp;
}
// Reset the anchor to point at itself
m_anchor.next = &m_anchor;
m_anchor.prev = &m_anchor;
m_count = 0;
}
// Clear: Clears the list. (Does not delete or release the list items.)
virtual void Clear()
{
NoOp<T> clearOp;
Clear<>(clearOp);
}
// Enumerator functions
POSITION FrontPosition()
{
if (IsEmpty())
{
return POSITION(nullptr);
}
else
{
return POSITION(Front());
}
}
POSITION EndPosition() const
{
return POSITION();
}
HRESULT GetItemPos(POSITION pos, T *ppItem)
{
if (pos.pNode)
{
return GetItem(pos.pNode, ppItem);
}
else
{
return E_FAIL;
}
}
POSITION Next(const POSITION pos)
{
if (pos.pNode && (pos.pNode->next != &m_anchor))
{
return POSITION(pos.pNode->next);
}
else
{
return POSITION(nullptr);
}
}
// Remove an item at a position.
// The item is returns in ppItem, unless ppItem is nullptr.
// NOTE: This method invalidates the POSITION object.
HRESULT Remove(POSITION& pos, T *ppItem)
{
if (pos.pNode)
{
// Remove const-ness temporarily...
Node *pNode = const_cast<Node*>(pos.pNode);
pos = POSITION();
return RemoveItem(pNode, ppItem);
}
else
{
return E_INVALIDARG;
}
}
};
// Typical functors for Clear method.
// ComAutoRelease: Releases COM pointers.
// MemDelete: Deletes pointers to new'd memory.
class ComAutoRelease
{
public:
void operator()(IUnknown *p)
{
if (p)
{
p->Release();
}
}
};
class MemDelete
{
public:
void operator()(void *p)
{
if (p)
{
delete p;
}
}
};
// ComPtrList class
// Derived class that makes it safer to store COM pointers in the List<> class.
// It automatically AddRef's the pointers that are inserted onto the list
// (unless the insertion method fails).
//
// T must be a COM interface type.
// example: ComPtrList<IUnknown>
//
// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can
// succeed but return a nullptr pointer. By default, the list does not allow nullptr
// pointers.
template <class T, bool NULLABLE = FALSE>
class ComPtrList : public List<T*>
{
public:
typedef T* Ptr;
void Clear()
{
ComAutoRelease car;
List<Ptr>::Clear(car);
}
~ComPtrList()
{
Clear();
}
protected:
HRESULT InsertAfter(Ptr item, Node *pBefore)
{
// Do not allow nullptr item pointers unless NULLABLE is true.
if (item == nullptr && !NULLABLE)
{
return E_POINTER;
}
if (item)
{
item->AddRef();
}
HRESULT hr = List<Ptr>::InsertAfter(item, pBefore);
if (FAILED(hr) && item != nullptr)
{
item->Release();
}
return hr;
}
HRESULT GetItem(const Node *pNode, Ptr* ppItem)
{
Ptr pItem = nullptr;
// The base class gives us the pointer without AddRef'ing it.
// If we return the pointer to the caller, we must AddRef().
HRESULT hr = List<Ptr>::GetItem(pNode, &pItem);
if (SUCCEEDED(hr))
{
assert(pItem || NULLABLE);
if (pItem)
{
*ppItem = pItem;
(*ppItem)->AddRef();
}
}
return hr;
}
HRESULT RemoveItem(Node *pNode, Ptr *ppItem)
{
// ppItem can be nullptr, but we need to get the
// item so that we can release it.
// If ppItem is not nullptr, we will AddRef it on the way out.
Ptr pItem = nullptr;
HRESULT hr = List<Ptr>::RemoveItem(pNode, &pItem);
if (SUCCEEDED(hr))
{
assert(pItem || NULLABLE);
if (ppItem && pItem)
{
*ppItem = pItem;
(*ppItem)->AddRef();
}
if (pItem)
{
pItem->Release();
pItem = nullptr;
}
}
return hr;
}
};

View File

@ -0,0 +1,222 @@
//////////////////////////////////////////////////////////////////////////
//
// OpQueue.h
// Async operation queue.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////
#pragma once
#pragma warning( push )
#pragma warning( disable : 4355 ) // 'this' used in base member initializer list
/*
This header file defines an object to help queue and serialize
asynchronous operations.
Background:
To perform an operation asynchronously in Media Foundation, an object
does one of the following:
1. Calls MFPutWorkItem(Ex), using either a standard work queue
identifier or a caller-allocated work queue. The work-queue
thread invokes the object's callback.
2. Creates an async result object (IMFAsyncResult) and calls
MFInvokeCallback to invoke the object's callback.
Ultimately, either of these cause the object's callback to be invoked
from a work-queue thread. The object can then complete the operation
inside the callback.
However, the Media Foundation platform may dispatch async callbacks in
parallel on several threads. Putting an item on a work queue does NOT
guarantee that one operation will complete before the next one starts,
or even that work items will be dispatched in the same order they were
called.
To serialize async operations that should not overlap, an object should
use a queue. While one operation is pending, subsequent operations are
put on the queue, and only dispatched after the previous operation is
complete.
The granularity of a single "operation" depends on the requirements of
that particular object. A single operation might involve several
asynchronous calls before the object dispatches the next operation on
the queue.
*/
//-------------------------------------------------------------------
// OpQueue class template
//
// Base class for an async operation queue.
//
// TOperation: The class used to describe operations. This class must
// implement IUnknown.
//
// The OpQueue class is an abstract class. The derived class must
// implement the following pure-virtual methods:
//
// - IUnknown methods (AddRef, Release, QI)
//
// - DispatchOperation:
//
// Performs the asynchronous operation specified by pOp.
//
// At the end of each operation, the derived class must call
// ProcessQueue to process the next operation in the queue.
//
// NOTE: An operation is not required to complete inside the
// DispatchOperation method. A single operation might consist
// of several asynchronous method calls.
//
// - ValidateOperation:
//
// Checks whether the object can perform the operation specified
// by pOp at this time.
//
// If the object cannot perform the operation now (e.g., because
// another operation is still in progress) the method should
// return MF_E_NOTACCEPTING.
//
//-------------------------------------------------------------------
#include "linklist.h"
#include "AsyncCB.h"
template <class T, class TOperation>
class OpQueue //: public IUnknown
{
public:
typedef ComPtrList<TOperation> OpList;
HRESULT QueueOperation(TOperation *pOp);
protected:
HRESULT ProcessQueue();
HRESULT ProcessQueueAsync(IMFAsyncResult *pResult);
virtual HRESULT DispatchOperation(TOperation *pOp) = 0;
virtual HRESULT ValidateOperation(TOperation *pOp) = 0;
OpQueue(CRITICAL_SECTION& critsec)
: m_OnProcessQueue(static_cast<T *>(this), &OpQueue::ProcessQueueAsync),
m_critsec(critsec)
{
}
virtual ~OpQueue()
{
}
protected:
OpList m_OpQueue; // Queue of operations.
CRITICAL_SECTION& m_critsec; // Protects the queue state.
AsyncCallback<T> m_OnProcessQueue; // ProcessQueueAsync callback.
};
//-------------------------------------------------------------------
// Place an operation on the queue.
// Public method.
//-------------------------------------------------------------------
template <class T, class TOperation>
HRESULT OpQueue<T, TOperation>::QueueOperation(TOperation *pOp)
{
HRESULT hr = S_OK;
EnterCriticalSection(&m_critsec);
hr = m_OpQueue.InsertBack(pOp);
if (SUCCEEDED(hr))
{
hr = ProcessQueue();
}
LeaveCriticalSection(&m_critsec);
return hr;
}
//-------------------------------------------------------------------
// Process the next operation on the queue.
// Protected method.
//
// Note: This method dispatches the operation to a work queue.
//-------------------------------------------------------------------
template <class T, class TOperation>
HRESULT OpQueue<T, TOperation>::ProcessQueue()
{
HRESULT hr = S_OK;
if (m_OpQueue.GetCount() > 0)
{
hr = MFPutWorkItem2(
MFASYNC_CALLBACK_QUEUE_STANDARD, // Use the standard work queue.
0, // Default priority
&m_OnProcessQueue, // Callback method.
nullptr // State object.
);
}
return hr;
}
//-------------------------------------------------------------------
// Process the next operation on the queue.
// Protected method.
//
// Note: This method is called from a work-queue thread.
//-------------------------------------------------------------------
template <class T, class TOperation>
HRESULT OpQueue<T, TOperation>::ProcessQueueAsync(IMFAsyncResult *pResult)
{
HRESULT hr = S_OK;
TOperation *pOp = nullptr;
EnterCriticalSection(&m_critsec);
if (m_OpQueue.GetCount() > 0)
{
hr = m_OpQueue.GetFront(&pOp);
if (SUCCEEDED(hr))
{
hr = ValidateOperation(pOp);
}
if (SUCCEEDED(hr))
{
hr = m_OpQueue.RemoveFront(nullptr);
}
if (SUCCEEDED(hr))
{
(void)DispatchOperation(pOp);
}
}
if (pOp != nullptr)
{
pOp->Release();
}
LeaveCriticalSection(&m_critsec);
return hr;
}
#pragma warning( pop )