opencore的文件识别(http://blog.csdn.net/jinlking/archive/2009/04/20/4095415.aspx)
2010-06-24 22:54
621 查看
原文地址:http://blog.csdn.net/jinlking/archive/2009/04/20/4095415.aspx
现在在看opencore的文件识别部分,看到高人的这篇文章,收获不少啊,赶紧收藏!
前面我们说了文件的打开,发送数据给下一个
peer
,但是我们还是不明白文件的格式是
如何识别的,因为文件的种类繁多,文件的识别就会很麻烦,并且还要考虑到可扩展性,所以这个文件的识别是以插件的形式来存在的,这里我们简要的说一下,这
个插件的框架。
由于文件的格式很多,而且标准也很多,很难
肯定某一文件就是某种的格式,因而就引入一个确信度的概念。
typedef
Oscl_Vector<OSCL_HeapString<OsclMemAllocator>,
OsclMemAllocator>
PVMFRecognizerMIMEStringList;
typedef enum
_PVMFRecognizerConfidence
{
PVMFRecognizerConfidenceNotCertain,
//
100% sure not the format
PVMFRecognizerConfidenceNotPossible,
//
Maybe not the format
PVMFRecognizerConfidenceUnknown,
//
Not sure one way or the other
PVMFRecognizerConfidencePossible,
//
Maybe the format
PVMFRecognizerConfidenceCertain
//
100% sure of the format
} PVMFRecognizerConfidence;
然后是文件识别的结果:
class PVMFRecognizerResult
{
public:
PVMFRecognizerResult()
{
};
// Copy constructor for use in Oscl_Vector
PVMFRecognizerResult(const PVMFRecognizerResult& aSrc)
{
iRecognizedFormat = aSrc.iRecognizedFormat;
iRecognitionConfidence = aSrc.iRecognitionConfidence;
//
iRecognizerSubFormatList=aSrc.iRecognizerSubFormatList;
};
~PVMFRecognizerResult()
{
};
// The format of interest as a MIME string
OSCL_HeapString<OsclMemAllocator> iRecognizedFormat;
// The confidence level of recognition
PVMFRecognizerConfidence iRecognitionConfidence;
// If the format is a container format, the format of content
within
//
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>
iRecognizerSubFormatList;
};
格式和确信度。
然后就是一个事件的监控者
Observer
。
/**
*
PVMFRecognizerCommmandHandler Class
*
*
PVMFRecognizerCommmandHandler is the PVMF Recognizer observer class for
notifying
the
*
status of asynchronous requests. The API provides a mechanism for the
status of
each
*
command to be passed back along with context specific information where
applicable.
*
User of the recognizer registry must have a class derived from
PVMFNodeCmdStatusObserver
*
and implement the pure virtual function in order to receive event
notifications
from
*
PVMF Recognizer Registry.
**/
class
PVMFRecognizerCommmandHandler
{
public:
/**
* Handle an event that has been generated.
*
* @param aResponse
*
The response to a
previously issued command
*/
virtual void RecognizerCommandCompleted(const PVMFCmdResp&
aResponse) = 0;
virtual ~PVMFRecognizerCommmandHandler() {}
};
#endif //
PVMF_RECOGNIZER_TYPES_H_INCLUDED
这些都只是纯虚类。
文件识别,一
般都是读取文件中的某些特殊的字节,然后才能做判断的,由于不同的文件读取的地方不同,并且识别的规则也是不同,所以定义一个基本的接口。
class
PVMFRecognizerPluginInterface
{
public:
/**
* Virtual destructor for the plug-in. All plug-ins should perform
any
clean up here
**/
virtual ~PVMFRecognizerPluginInterface()
{
};
/**
* This methods returns a list of format(s) that this plug-in can
recognize. Each supported format
* is represented by a MIME string.
*
* @param aSupportedFormatsList
*
Reference to a list of
MIME strings which will be filled in with list of formats that the
plug-in can
recognize.
*
* @exception This method can leave with one of the following
error codes
*
OsclErrNoMemory if
memory cannot be allocated for the format list
*
* @returns A PVMF status code to report result of method
**/
本插件支持下面的一些
格式的识别,以一个列表的形式返回
注意我们的文件识别都是以
插件的形式存在的,这样就可以保证文件识别的可扩展性,每一个插件都必须从这个接口来继承,另外还必须有一个类统一管理这些插件,如插件的查找和注册
virtual PVMFStatus
SupportedFormats(PVMFRecognizerMIMEStringList&
aSupportedFormatsList) = 0;
/**
* This method determines the the specified content is or is not
one of
the formats recognized by this plug-in
*
* @param aSourceDataStreamFactory
*
A reference to a
PVMFDataStreamFactory representing the content to recognize
* @param aFormatHint
*
An optional input
parameter expressed as a list of MIME string which provides a priori
hint for
the format
*
of the content specified
by aSourceDataStreamFactory.
* @param aRecognizerResult
*
An output parameter which
is a reference to a vector of PVMFRecognizerResult that will contain the
recognition
*
result if the Recognize()
method succeeds.
*
* @exception This method can leave with one of the following
error codes
*
* @returns A PVMF status code to report result of method
**/
//
给定一个数据源让你去识别,有一个优先考虑的格式列表参数,返回的是
一个识别结果的列表,列出可能的格式和确信度。
virtual PVMFStatus
Recognize(PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHint,
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>& aRecognizerResult) = 0;
/**
* This method returns the mininum required bytes in datastream
for this
plug-in
* to be able to recognize its supported formats.
*
* @param aBytes[out]
*
A reference to a minimum
required bytes
*
* @returns A PVMF status code to report result of method.
* PVMFSuccess in case of success and PVMFFailure otherwise.
**///
或者识别所需的最小字节数
virtual PVMFStatus
GetRequiredMinBytesForRecognition(uint32& aBytes) = 0;
};
每一个插件都
需要占用一定内存,因而就有下面的定义:一个插件的工厂的基类,每一个插件都要有一个这样的工厂接口来创建和删除某一个插件。
/**
*
An abstract base class to create and destroy
a recognizer plug-in. Every recognizer plug-in should have
*
an associated factory class to provide a
standard way to create and destroy the plug-in.
**/
class
PVMFRecognizerPluginFactory: public
HeapBase
{
public:
/**
* Virtual destructor for the plug-in
factory. All plug-in factory should perform any clean up here
**/
virtual ~PVMFRecognizerPluginFactory()
{
};
/**
* This method instantiates and returns
the recognizer plug-in that the factory is associated with.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for the recognizer plug-in
* @returns A pointer to the recognizer
plug-in instance if creation is successful.
**/
virtual PVMFRecognizerPluginInterface* CreateRecognizerPlugin() =
0;
/**
* This method destroys the specified
recognizer plug-in pointer as the particular recognizer plug-in
* the factory is associated with.
*
* @param aPlugIn
*
A pointer to the recognizer plug-in
that should be destroyed.
*
* @exception This method can leave
with one of the following error codes
*
* @returns None
**/
virtual void
DestroyRecognizerPlugin(PVMFRecognizerPluginInterface*
aPlugIn) = 0;
};
然后就是一个
模板的定义,因为插件很多,这里我们写一个简单的模板:
/**
*
Basic templatized recognizer plug-in factory. Can be used if the
recognizer
plug-in only needs
* to
be instantiated and destroyed by just new and delete, respectively and
no other
functionality
* is
needed from the factory class.
**/
template<class T>
class
PVMFRecognizerPluginFactoryBasic :
public PVMFRecognizerPluginFactory
{
public:
virtual ~PVMFRecognizerPluginFactoryBasic()
{
};
PVMFRecognizerPluginInterface* CreateRecognizerPlugin()
{
T* plugin = OSCL_NEW(T, ());
return plugin;
};
void DestroyRecognizerPlugin(PVMFRecognizerPluginInterface*
aPlugIn)
{
T* plugin = (T*)aPlugIn;
OSCL_DELETE(plugin);
};
};
这样关于插件
的基类,我们基本搞定,下面的就是这么多插件在一起如何去管理。这里就是一个静态类(
static
)。负责插件的注册和注销,并且负责文件的的寻找,来了文件,历遍所有注册过的插件来找到最匹配的格式。这和微软的
DirectShow
框架极为相似,不过微软的
Filter
是这侧到注册表里面去了,并且,微软
Filter
的概念不仅仅是文件的识别,在微软的注册表中,有一项就是
Media Type
,规定了系统所能够识别的文件类型,每一个类型都要有匹配码,例如前面
八个字节是什么,后面四个字节是什么,这些都是在注册表中,注册的另外的一个就是打开这个文件所需的
Source Filter
的
ID
,这样要播放的文件的时候按照一定优先级匹配这些注册信息就行了。
这里关于插件
的管理有一个单独的静态类,静态类的特点就是不管类是不是存在,这个东西都是存在的,并且全局可访问。这才是我们识别的关键代码:
/**
* A
class of static methods that provides the interface to the PVMF
recognizer
registry..
*
With these static methods, the recognizer registry can be initialized
and
shutdown, recognizer
*
plug-ins can be registered and unregistered, and format of a content can
be
recognized.
**/
class PVMFRecognizerRegistry
{
public:
/**
格式的注册信息的初始化,
因为我们知道,一种格式的识别,都会注册相应的信息,识别器就是通过这些信息的历遍,找出对应的文件。在使用识别器之前,最先就是初始化。
* This static method initializes the
recognizer registry for use. This method must be called once
* and succeed before calling any other
methods from PVMFRecognizerRegistry.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for the registry implementation
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus Init();
/**
使用完之后,
就要清空
* This static methods shuts down and
cleans up the recognizer registry. This method must be called once
* after there is no more use for the
recognizer registry to properly release the memory allocated for the
* registry
**/
OSCL_IMPORT_REF static void Cleanup();
/**
一种媒体格式识别信息的添
加,实际上就是添加一个
PVMFRecognizerPluginFactory
,前面我们说过每一种格式都会有其对应的
PVMFRecognizerPluginFactory
。
* This static method adds the
specified recognizer plug-in factory to the list of available
recognizers.
* The passed-in plug-in factory would
be used to create and destroy the recognizer plug-in in the Recognize()
methods.
* The passed-in plug-in factory
reference must be valid until it is removed from the list by the
RemovePlugin()
method.
*
* @param aPluginFactory
*
A reference to a recognizer plug-in
factory to add to the list of registered recognizers
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for vector holding the plug-in factory pointers
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus
RegisterPlugin(PVMFRecognizerPluginFactory& aPluginFactory);
/**
注销某一种格式,将某一种识别的信息从注册信息列表中剔除
* This static method removes the
specified recognizer plug-in factory from the list of available
recognizers.
* The passed-in plug-in factory must
have been added before with RegisterPlugin() for this method to succeed.
* After the plug-in factory is
successfully removed, the factory instance can be deleted.
*
* @param aPluginFactory
*
A reference to a recognizer plug-in
factory to remove from the list of registered recognizers
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus
RemovePlugin(PVMFRecognizerPluginFactory& aPluginFactory);
/**
* This static method creates a recognition
session with the recognizer framework.
*
创建一个识别的会话,
* @param aSessionId
返回一个会话的
ID
*
A reference to a PVMFSessionId which
will be set to the session's unique identifier when this method
*
completes successfully.
* @param aCmdHandler
给它一个识别的观察者,也就是消息的监控者
*
A reference to a
PVMFRecognizerCommmandHandler which will receive asynchronous command
completion notification.
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus OpenSession(PVMFSessionId&
aSessionId, PVMFRecognizerCommmandHandler& aCmdHandler);
/**
* This static method shuts down a
recognition session with the recognizer framework.
*
关闭一个会话
* @param aSessionId
*
The unique identifier of the session to
close
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus CloseSession(PVMFSessionId
aSessionId);
/**
开始识别,开始识别的开始就需要一个数据的来源、然后是优先考虑的格
式、识别结果的存储、
* This static method asynchronously
determines the format of the specified content using the currently
registered
* recognizer plug-ins. When the
recognizer request completes, the user would be notified via the
PVMFRecognizerCommandHandler
* callback handler set when opening
the session.
*
* @param aSessionId
*
The unique identifier for the
recognizer session
* @param aSourceDataStreamFactory
数据的来源
*
A reference to a PVMFDataStreamFactory
representing the content to recognize
* @param aFormatHintList
优先考虑的格式
*
An optional input parameter expressed
as a list of MIME string which provides a priori hint for the format
*
of the content specified by
aSourceDataStreamFactory.
* @param aRecognizerResult
结果的存储
*
An output parameter which is a
reference to a vector of PVMFRecognizerResult that will contain the
recognition
*
result if the Recognize()
method succeeds.
* @param aCmdContext
*
Optional pointer to opaque data that
will be returned in the command completion response
,识别上下文的返回
* @param aTimeout
识别的时间限制
*
Optional timeout value for the
recognition request. If the recognition operation takes more time than
the
timeout
*
value, the operation will be cancelled
with PVMFErrTimeout status code. If the timeout value is set to 0, the
*
recognition operation will go to
completion.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot
allocated to process this request
*
OsclErrArgument if one or more of the
passed-in parameters is invalid
*
* @returns A PVMF command ID for the
recognize request
**/
OSCL_IMPORT_REF static PVMFCommandId Recognize(PVMFSessionId
aSessionId,
PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHintList,
Oscl_Vector<PVMFRecognizerResult, OsclMemAllocator>&
aRecognizerResult, OsclAny* aCmdContext = NULL, uint32 aTimeout = 0);
/**
取消前一个异步的识别操作
* This static method cancels a
previously issued asynchronous request that hasn't completed yet.
*
* @param aSessionId
*
The unique identifier for the
recognizer session
* @param aCommandToCancelId
*
Unique identifier for the asynchronous
request to cancel.
* @param aCmdContext
*
Optional pointer to opaque data that
will be returned in the command completion response
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot
allocated to process this request
*
OsclErrArgument if one or more of the
passed-in parameters is invalid
*
* @returns A PVMF command ID for the
cancel request
**/
OSCL_IMPORT_REF static PVMFCommandId CancelCommand(PVMFSessionId
aSessionId, PVMFCommandId aCommandToCancelId, OsclAny* aCmdContext =
NULL);
};
这样我们的识
别文件格式的框架就完成了。下面看一些具体的实现。
很遗憾,在
OSDL
中,我们已经定义好了一个类似于微软注册表的东西,它存在与
OSDL
中,在
OSDL
之上的任何代码都是可以访问的。
class
OsclTLSRegistry
{
public:
/*
** Get an entry
** @param ID: identifier
** @param error (output) 0 for success
or an error from TPVBasePanicEnum
** @returns: the entry value
*/
OSCL_IMPORT_REF static OsclAny*
getInstance(uint32 ID, int32 &error);
/*
** Set an entry
** @param ID: identifier
** @param error (output) 0 for success
or an error from TPVBasePanicEnum
** @returns: the entry value
*/
OSCL_IMPORT_REF static void
registerInstance(OsclAny* ptr, uint32 ID, int32 &error);
private:
OsclTLSRegistry()
{}
typedef OsclAny* registry_type;
typedef registry_type*
registry_pointer_type;
#if (
OSCL_TLS_IS_KEYED)
class TKeyItem
{
public:
TKeyItem(): iTlsKey(NULL),
iThreadId(0)
{}
TOsclTlsKey *iTlsKey;
TOsclTlsThreadId iThreadId;
};
class TlsKeyTable
{
public:
TlsKeyTable(): iNumKeys(0)
{}
_OsclBasicLock iLock;
uint32 iNumKeys;
TKeyItem iKeys[OSCL_TLS_MAX_THREADS];
};
//The key table is a global variable.
static TlsKeyTable* iTlsKeyTable;
static void
GetThreadId(TOsclTlsThreadId &threadId, int32&);
static TOsclTlsKey*
LookupTlsKey(int32&);
static bool SaveTlsKey(TOsclTlsKey*
key, int32&);
static bool
RemoveTlsKey(Oscl_DefAlloc& alloc, TOsclTlsKey* key, int32&);
#endif
private:
OSCL_IMPORT_REF static void
initialize(Oscl_DefAlloc &alloc, int32 &error);
OSCL_IMPORT_REF static void cleanup(Oscl_DefAlloc
&alloc, int32 &error);
friend class OsclBase;
};
这个类的实现
可以参见具体的代码,所以这里我们就不去多说。这里我们在注册信息中填入的是一个什么呢?
我们看静态的
初始化函数。
OSCL_EXPORT_REF PVMFStatus
PVMFRecognizerRegistry::Init()
{
// Check that there is no existing registry
PVMFRecognizerRegistryImpl*
pvrecregimpl
= OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
//
如果存在,那么我就不用注册这个一项了
if (pvrecregimpl != NULL)
{
// Registry is already present so no need to instantiate again
// Just increment the refcount
(pvrecregimpl->iRefCount)++;
return PVMFSuccess;
}
// Instantiate the
registry implementation
,否则就开始分配新的空间开始注册
Oscl_TAlloc<PVMFRecognizerRegistryImpl, OsclMemAllocator>
talloc;
pvrecregimpl = OSCL_ALLOC_NEW(talloc, PVMFRecognizerRegistryImpl,
());
// Save it on singleton or TLS
PVMFRECOGNIZER_REGISTRY::registerInstance(pvrecregimpl,
PVMFRECOGNIZER_REGISTRY_ID);
return PVMFSuccess;
}
继续往下面讲之前,我觉得我们可以看一下
PVMFRecognizerRegistryImpl
,这个是怎么实现的,
PVMFRecognizerRegistryImpl
是我们注册表中保存的一个东东。主要实现文件的识别,包含很多的信息。我以前以为只有变量才能注册
的,其实函数也能注册的,函数代码的空间也是数据,是数据就有指针,所以整个类也是可以注册的。注册后,如果要清空,那么就要调用
Cleanup
,
OSCL_EXPORT_REF void
PVMFRecognizerRegistry::Cleanup()
{
// Retrieve the registry implementation instance
from
singleton or TLS and destroy it
首先单件模式,返回我们注册的
PVMFRecognizerRegistryImpl
指针,这个指针指向的内容是存在的,因为我们前面在初始化的时候就分
配了内存
PVMFRecognizerRegistryImpl* pvrecregimpl =
OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
if (pvrecregimpl != NULL)
{
// First decrement
the refcount
,
直接自减就行了,自身负责分配
--(pvrecregimpl->iRefCount);
// If
the resulting refcount is 0, then delete the instance
if ((pvrecregimpl->iRefCount) <= 0)
{
Oscl_TAlloc<PVMFRecognizerRegistryImpl, OsclMemAllocator>
talloc;
OSCL_ALLOC_DELETE(pvrecregimpl, talloc,
PVMFRecognizerRegistryImpl);
// Unregister by putting NULL pointer
in
singleton or TLS
释放后,注意把注册表中的信息清空
PVMFRECOGNIZER_REGISTRY::registerInstance(NULL,
PVMFRECOGNIZER_REGISTRY_ID);
}
}
else
{
// Registry has already been cleaned up so nothing to do
}
}
然后就是注册我们的文件识别组件
OSCL_EXPORT_REF PVMFStatus
PVMFRecognizerRegistry::RegisterPlugin(PVMFRecognizerPluginFactory&
aPluginFactory)
{
PVMFRecognizerRegistryImpl* pvrecregimpl =
OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
if (pvrecregimpl != NULL)
{
return
pvrecregimpl->RegisterPlugin(aPluginFactory);
}
else
{
// Registry hasn't been initialized yet. Assert
OSCL_ASSERT(false);
return PVMFErrNotReady;
}
}
其实很简单,调用对应的成员就行了。
下面的几个函数基本上都是这样子了,
RemovePlugin
、
OpenSession
、
CloseSession
、
Recognize
、
CancelCommand
。
下面我们看看
PVMFRecognizerRegistryImpl
的实现。
因为文件的识别是一个比较“卡”的过程,为
了不让我们的软件给人很卡的感官,我们这里把这个类另辟一个线程来进行,并且以异步的方式来调用,通过命令。
识别的命令有下面的两种类型:
/**
*
PVMFRecRegImplCommandType enum
*
*
Enumeration of commands that can be issued to the PVMF Recognizer
Registry
*
**/
typedef enum
{
PVMFRECREG_COMMAND_RECOGNIZE = 1,
PVMFRECREG_COMMAND_CANCELCOMMAND,
} PVMFRecRegImplCommandType;
一个就是开始识别,一个就是取消识别。
class PVMFRecRegSessionInfo
{
public:
PVMFRecRegSessionInfo()
{
};
PVMFRecRegSessionInfo(const PVMFRecRegSessionInfo& aSrc)
{
iRecRegSessionId = aSrc.iRecRegSessionId;
iRecRegCmdHandler = aSrc.iRecRegCmdHandler;
};
~PVMFRecRegSessionInfo()
{
};
PVMFSessionId iRecRegSessionId;
PVMFRecognizerCommmandHandler* iRecRegCmdHandler;
};
识别的一个信
息的保存,一个事识别的
sessionID
,一个事事件处理。
下面就是一个
命令的具体的封装,包含一个参数的列表
/**
*
PVMFRecRegImplCommand Class
*
*
PVMFRecRegImplCommand class is a data class
to hold issued commands inside the recognizer registry impl
**/
class PVMFRecRegImplCommand
{
public:
/**
* The constructor for
PVMFRecRegImplCommand which allows the data values to be set.
*
* @param aCmdType The command type
value for this command.
* @param aCmdId The command ID
assigned for this command.
* @param aContextData The pointer to
the passed-in context data for this command.
* @param aParamVector The optional pointer to a list of
parameters
*
* @returns None
**/
初始化就是一个参数
列表
PVMFRecRegImplCommand(PVMFSessionId aSessionId, int32 aCmdType,
PVMFCommandId aCmdId, OsclAny* aContextData = NULL,
Oscl_Vector<PVMFRecRegImplCommandParamUnion,
OsclMemAllocator>*
aParamVector = NULL, bool aAPICommand = true) :
iSessionId(aSessionId),
iCmdType(aCmdType),
iCmdId(aCmdId), iContextData(aContextData), iAPICommand(aAPICommand)
{
iParamVector.clear();
if (aParamVector)
{
iParamVector
= *aParamVector;
}
}
/**
* The copy constructor for
PVMFRecRegImplCommand. Used mainly for Oscl_Vector.
*
* @param aCmd The reference to the
source PVMFRecRegImplCommand to copy the data values from.
*
* @returns None
**/
PVMFRecRegImplCommand(const PVMFRecRegImplCommand& aCmd)
{
iSessionId = aCmd.iSessionId;
iCmdType = aCmd.iCmdType;
iCmdId = aCmd.iCmdId;
iContextData = aCmd.iContextData;
iAPICommand = aCmd.iAPICommand;
iParamVector = aCmd.iParamVector;
}
/**
* This function returns the session ID
for the command
*
* @returns The session ID value for
this command.
**/
PVMFSessionId GetSessionId()const
{
return iSessionId;
}
/**
* This function returns the stored
command type value.
*
* @returns The signed 32-bit command
type value for this command.
**/
int32 GetCmdType()const
{
return iCmdType;
}
/**
* This function returns the stored
command ID value.
*
* @returns The PVMFCommandId value for
this command.
**/
PVMFCommandId GetCmdId()const
{
return iCmdId;
}
/**
* This function returns the stored
context data pointer.
*
* @returns The pointer to the context
data for this command
**/
OsclAny* GetContext()const
{
return iContextData;
}
/**
* This function tells whether the
command is an API command or not
*
* @returns true if API command, false
if not.
**/
bool IsAPICommand()const
{
return iAPICommand;
}
/**
* This function returns the command
parameter from the specified index.
* If the specified index is not
available, empty parameter will be returned
*
* @param aIndex The index of the
parameter to return
*
* @returns The stored parameter for
this command
**/
PVMFRecRegImplCommandParamUnion GetParam(uint32 aIndex)const
{
if (aIndex >= iParamVector.size())
{
PVMFRecRegImplCommandParamUnion
param;
oscl_memset(¶m,
0,
sizeof(PVMFRecRegImplCommandParamUnion));
return
param;
}
else
{
return
iParamVector[aIndex];
}
}
bool operator==(const PVMFRecRegImplCommand& x)const
{
return iCmdId == x.iCmdId;
}
PVMFSessionId iSessionId;
int32 iCmdType;
PVMFCommandId iCmdId;
OsclAny* iContextData;
bool iAPICommand;
Oscl_Vector<PVMFRecRegImplCommandParamUnion,
OsclMemAllocator> iParamVector;
};
上面就是一个带参数的识别命令。
然后有一个优先级的比较:
class
PVMFRecRegImplCommandCompareLess
{
public:
/**
* The algorithm used in
OsclPriorityQueue needs a compare function
*
that returns true when A's priority is less than B's
* @return true if A's priority is less
than B's, else false
*/
int compare(PVMFRecRegImplCommand& a,
PVMFRecRegImplCommand& b)
const
{
int a_pri = PVMFRecRegImplCommandCompareLess::GetPriority(a);
int b_pri = PVMFRecRegImplCommandCompareLess::GetPriority(b);
if (a_pri < b_pri)
{
//
Higher priority
return
true;
}
else if (a_pri == b_pri)
{
//
Same priority so look at the
command ID to maintain FIFO
return
(a.GetCmdId() >
b.GetCmdId());
}
else
{
//
Lower priority
return false;
}
}
/**
* Returns the priority of each command
* @return A 0-based priority number. A
lower number indicates lower priority.
*/
static int GetPriority(PVMFRecRegImplCommand& aCmd)
{
switch (aCmd.GetCmdType())
{
case
PVMFRECREG_COMMAND_RECOGNIZE:
return
5;
case
PVMFRECREG_COMMAND_CANCELCOMMAND:
return
3;
default:
return
0;
}
}
};
如何识别的?
/**
* Implementation of the recognizer registry.
The recognizer interface class should only
* use this class.
**/
这里为什么要
从
PvmiDataStreamObserver
来继承,因为我们的识别就必须读取一部分的字节,必然会有相关的
data
数据流的操作,这里是一个简单的事件监控。为什么要从
OsclTimerObject
,因为我们识别是单开线程的,并且识别有一个时间的上线。
class
PVMFRecognizerRegistryImpl : public OsclTimerObject,
public PvmiDataStreamObserver
{
public:
PVMFRecognizerRegistryImpl();
~PVMFRecognizerRegistryImpl();
注册和注销识
别插件
PVMFStatus
RegisterPlugin(PVMFRecognizerPluginFactory& aPluginFactory);
PVMFStatus
RemovePlugin(PVMFRecognizerPluginFactory& aPluginFactory);
PVMFStatus
OpenSession(PVMFSessionId& aSessionId,
PVMFRecognizerCommmandHandler&
aCmdHandler);
PVMFStatus CloseSession(PVMFSessionId
aSessionId);
识别
PVMFCommandId Recognize(PVMFSessionId
aSessionId, PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHint,
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>&
aRecognizerResult, OsclAny* aCmdContext, uint32
aTimeout);
PVMFCommandId
CancelCommand(PVMFSessionId aSessionId, PVMFCommandId
aCommandToCancelId,
OsclAny* aCmdContext);
// Reference count for the registry
implementation
int32 iRefCount;
注册的
Plug
个数
private:
这个我怀疑是这样的,同时可能有多个识别的操作,那么就需要列表处理
PVMFSessionId iNextSessionId;
PVMFCommandId iNextCommandId;
// From OsclTimerObject
void Run();
// Vector to hold the active sessions
Oscl_Vector<PVMFRecRegSessionInfo,
OsclMemAllocator> iRecognizerSessionList;
// Vector to hold the available
recognizer plug-in
Oscl_Vector<PVMFRecognizerPluginFactory*, OsclMemAllocator>
iRecognizerPluginFactoryList;
int32
FindPluginFactory(PVMFRecognizerPluginFactory& aFactory);
PVMFRecognizerPluginInterface*
CreateRecognizerPlugin(PVMFRecognizerPluginFactory& aFactory);
void
DestroyRecognizerPlugin(PVMFRecognizerPluginFactory& aFactory,
PVMFRecognizerPluginInterface* aPlugin);
// Vector to hold pending, current,
and
to-cancel commands
OsclPriorityQueue<PVMFRecRegImplCommand, OsclMemAllocator,
Oscl_Vector<PVMFRecRegImplCommand, OsclMemAllocator>,
PVMFRecRegImplCommandCompareLess>
iRecognizerPendingCmdList;
Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator> iRecognizerCurrentCmd;
Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator> iRecognizerCmdToCancel;
PVMFCommandId
AddRecRegCommand(PVMFSessionId
aSessionId, int32 aCmdType, OsclAny* aContextData = NULL,
Oscl_Vector<PVMFRecRegImplCommandParamUnion, OsclMemAllocator>*
aParamVector = NULL, bool aAPICommand = true);
void
CompleteCurrentRecRegCommand(PVMFStatus aStatus, const uint32
aCurrCmdIndex =
0, PVInterface* aExtInterface = NULL);
bool
FindCommandByID(Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator>
&aCmdQueue, const PVMFCommandId aCmdId);
// Command handling functions
void DoRecognize();
void CompleteRecognize(PVMFStatus
aStatus);
void
DoCancelCommand(PVMFRecRegImplCommand& aCmd);
PVMFDataStreamFactory*
iDataStreamFactory;
PVMIDataStreamSyncInterface*
iDataStream;
PvmiDataStreamSession
iDataStreamSessionID;
PvmiDataStreamCommandId
iRequestReadCapacityNotificationID;
PVMFStatus
GetMaxRequiredSizeForRecognition(uint32& aMaxSize);
PVMFStatus
GetMinRequiredSizeForRecognition(uint32& aMinSize);
PVMFStatus CheckForDataAvailability();
//logger
PVLogger* iLogger;
/* From PvmiDataStreamObserver */
void DataStreamCommandCompleted(const
PVMFCmdResp& aResponse);
void
DataStreamInformationalEvent(const
PVMFAsyncEvent& aEvent);
void DataStreamErrorEvent(const
PVMFAsyncEvent& aEvent);
bool oRecognizePending;
PVMFStatus iDataStreamCallBackStatus;
};
这个函数具体是如何实现的,有兴趣的可以继续看一下,我小看了一下,基本上就是一个
for
循环识别文件的格式。并且这种框架
很容易扩展新的文件格式。不错不错。具体的文件
plug
怎么写,后面继续。
现在在看opencore的文件识别部分,看到高人的这篇文章,收获不少啊,赶紧收藏!
前面我们说了文件的打开,发送数据给下一个
peer
,但是我们还是不明白文件的格式是
如何识别的,因为文件的种类繁多,文件的识别就会很麻烦,并且还要考虑到可扩展性,所以这个文件的识别是以插件的形式来存在的,这里我们简要的说一下,这
个插件的框架。
由于文件的格式很多,而且标准也很多,很难
肯定某一文件就是某种的格式,因而就引入一个确信度的概念。
typedef
Oscl_Vector<OSCL_HeapString<OsclMemAllocator>,
OsclMemAllocator>
PVMFRecognizerMIMEStringList;
typedef enum
_PVMFRecognizerConfidence
{
PVMFRecognizerConfidenceNotCertain,
//
100% sure not the format
PVMFRecognizerConfidenceNotPossible,
//
Maybe not the format
PVMFRecognizerConfidenceUnknown,
//
Not sure one way or the other
PVMFRecognizerConfidencePossible,
//
Maybe the format
PVMFRecognizerConfidenceCertain
//
100% sure of the format
} PVMFRecognizerConfidence;
然后是文件识别的结果:
class PVMFRecognizerResult
{
public:
PVMFRecognizerResult()
{
};
// Copy constructor for use in Oscl_Vector
PVMFRecognizerResult(const PVMFRecognizerResult& aSrc)
{
iRecognizedFormat = aSrc.iRecognizedFormat;
iRecognitionConfidence = aSrc.iRecognitionConfidence;
//
iRecognizerSubFormatList=aSrc.iRecognizerSubFormatList;
};
~PVMFRecognizerResult()
{
};
// The format of interest as a MIME string
OSCL_HeapString<OsclMemAllocator> iRecognizedFormat;
// The confidence level of recognition
PVMFRecognizerConfidence iRecognitionConfidence;
// If the format is a container format, the format of content
within
//
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>
iRecognizerSubFormatList;
};
格式和确信度。
然后就是一个事件的监控者
Observer
。
/**
*
PVMFRecognizerCommmandHandler Class
*
*
PVMFRecognizerCommmandHandler is the PVMF Recognizer observer class for
notifying
the
*
status of asynchronous requests. The API provides a mechanism for the
status of
each
*
command to be passed back along with context specific information where
applicable.
*
User of the recognizer registry must have a class derived from
PVMFNodeCmdStatusObserver
*
and implement the pure virtual function in order to receive event
notifications
from
*
PVMF Recognizer Registry.
**/
class
PVMFRecognizerCommmandHandler
{
public:
/**
* Handle an event that has been generated.
*
* @param aResponse
*
The response to a
previously issued command
*/
virtual void RecognizerCommandCompleted(const PVMFCmdResp&
aResponse) = 0;
virtual ~PVMFRecognizerCommmandHandler() {}
};
#endif //
PVMF_RECOGNIZER_TYPES_H_INCLUDED
这些都只是纯虚类。
文件识别,一
般都是读取文件中的某些特殊的字节,然后才能做判断的,由于不同的文件读取的地方不同,并且识别的规则也是不同,所以定义一个基本的接口。
class
PVMFRecognizerPluginInterface
{
public:
/**
* Virtual destructor for the plug-in. All plug-ins should perform
any
clean up here
**/
virtual ~PVMFRecognizerPluginInterface()
{
};
/**
* This methods returns a list of format(s) that this plug-in can
recognize. Each supported format
* is represented by a MIME string.
*
* @param aSupportedFormatsList
*
Reference to a list of
MIME strings which will be filled in with list of formats that the
plug-in can
recognize.
*
* @exception This method can leave with one of the following
error codes
*
OsclErrNoMemory if
memory cannot be allocated for the format list
*
* @returns A PVMF status code to report result of method
**/
本插件支持下面的一些
格式的识别,以一个列表的形式返回
注意我们的文件识别都是以
插件的形式存在的,这样就可以保证文件识别的可扩展性,每一个插件都必须从这个接口来继承,另外还必须有一个类统一管理这些插件,如插件的查找和注册
virtual PVMFStatus
SupportedFormats(PVMFRecognizerMIMEStringList&
aSupportedFormatsList) = 0;
/**
* This method determines the the specified content is or is not
one of
the formats recognized by this plug-in
*
* @param aSourceDataStreamFactory
*
A reference to a
PVMFDataStreamFactory representing the content to recognize
* @param aFormatHint
*
An optional input
parameter expressed as a list of MIME string which provides a priori
hint for
the format
*
of the content specified
by aSourceDataStreamFactory.
* @param aRecognizerResult
*
An output parameter which
is a reference to a vector of PVMFRecognizerResult that will contain the
recognition
*
result if the Recognize()
method succeeds.
*
* @exception This method can leave with one of the following
error codes
*
* @returns A PVMF status code to report result of method
**/
//
给定一个数据源让你去识别,有一个优先考虑的格式列表参数,返回的是
一个识别结果的列表,列出可能的格式和确信度。
virtual PVMFStatus
Recognize(PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHint,
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>& aRecognizerResult) = 0;
/**
* This method returns the mininum required bytes in datastream
for this
plug-in
* to be able to recognize its supported formats.
*
* @param aBytes[out]
*
A reference to a minimum
required bytes
*
* @returns A PVMF status code to report result of method.
* PVMFSuccess in case of success and PVMFFailure otherwise.
**///
或者识别所需的最小字节数
virtual PVMFStatus
GetRequiredMinBytesForRecognition(uint32& aBytes) = 0;
};
每一个插件都
需要占用一定内存,因而就有下面的定义:一个插件的工厂的基类,每一个插件都要有一个这样的工厂接口来创建和删除某一个插件。
/**
*
An abstract base class to create and destroy
a recognizer plug-in. Every recognizer plug-in should have
*
an associated factory class to provide a
standard way to create and destroy the plug-in.
**/
class
PVMFRecognizerPluginFactory: public
HeapBase
{
public:
/**
* Virtual destructor for the plug-in
factory. All plug-in factory should perform any clean up here
**/
virtual ~PVMFRecognizerPluginFactory()
{
};
/**
* This method instantiates and returns
the recognizer plug-in that the factory is associated with.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for the recognizer plug-in
* @returns A pointer to the recognizer
plug-in instance if creation is successful.
**/
virtual PVMFRecognizerPluginInterface* CreateRecognizerPlugin() =
0;
/**
* This method destroys the specified
recognizer plug-in pointer as the particular recognizer plug-in
* the factory is associated with.
*
* @param aPlugIn
*
A pointer to the recognizer plug-in
that should be destroyed.
*
* @exception This method can leave
with one of the following error codes
*
* @returns None
**/
virtual void
DestroyRecognizerPlugin(PVMFRecognizerPluginInterface*
aPlugIn) = 0;
};
然后就是一个
模板的定义,因为插件很多,这里我们写一个简单的模板:
/**
*
Basic templatized recognizer plug-in factory. Can be used if the
recognizer
plug-in only needs
* to
be instantiated and destroyed by just new and delete, respectively and
no other
functionality
* is
needed from the factory class.
**/
template<class T>
class
PVMFRecognizerPluginFactoryBasic :
public PVMFRecognizerPluginFactory
{
public:
virtual ~PVMFRecognizerPluginFactoryBasic()
{
};
PVMFRecognizerPluginInterface* CreateRecognizerPlugin()
{
T* plugin = OSCL_NEW(T, ());
return plugin;
};
void DestroyRecognizerPlugin(PVMFRecognizerPluginInterface*
aPlugIn)
{
T* plugin = (T*)aPlugIn;
OSCL_DELETE(plugin);
};
};
这样关于插件
的基类,我们基本搞定,下面的就是这么多插件在一起如何去管理。这里就是一个静态类(
static
)。负责插件的注册和注销,并且负责文件的的寻找,来了文件,历遍所有注册过的插件来找到最匹配的格式。这和微软的
DirectShow
框架极为相似,不过微软的
Filter
是这侧到注册表里面去了,并且,微软
Filter
的概念不仅仅是文件的识别,在微软的注册表中,有一项就是
Media Type
,规定了系统所能够识别的文件类型,每一个类型都要有匹配码,例如前面
八个字节是什么,后面四个字节是什么,这些都是在注册表中,注册的另外的一个就是打开这个文件所需的
Source Filter
的
ID
,这样要播放的文件的时候按照一定优先级匹配这些注册信息就行了。
这里关于插件
的管理有一个单独的静态类,静态类的特点就是不管类是不是存在,这个东西都是存在的,并且全局可访问。这才是我们识别的关键代码:
/**
* A
class of static methods that provides the interface to the PVMF
recognizer
registry..
*
With these static methods, the recognizer registry can be initialized
and
shutdown, recognizer
*
plug-ins can be registered and unregistered, and format of a content can
be
recognized.
**/
class PVMFRecognizerRegistry
{
public:
/**
格式的注册信息的初始化,
因为我们知道,一种格式的识别,都会注册相应的信息,识别器就是通过这些信息的历遍,找出对应的文件。在使用识别器之前,最先就是初始化。
* This static method initializes the
recognizer registry for use. This method must be called once
* and succeed before calling any other
methods from PVMFRecognizerRegistry.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for the registry implementation
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus Init();
/**
使用完之后,
就要清空
* This static methods shuts down and
cleans up the recognizer registry. This method must be called once
* after there is no more use for the
recognizer registry to properly release the memory allocated for the
* registry
**/
OSCL_IMPORT_REF static void Cleanup();
/**
一种媒体格式识别信息的添
加,实际上就是添加一个
PVMFRecognizerPluginFactory
,前面我们说过每一种格式都会有其对应的
PVMFRecognizerPluginFactory
。
* This static method adds the
specified recognizer plug-in factory to the list of available
recognizers.
* The passed-in plug-in factory would
be used to create and destroy the recognizer plug-in in the Recognize()
methods.
* The passed-in plug-in factory
reference must be valid until it is removed from the list by the
RemovePlugin()
method.
*
* @param aPluginFactory
*
A reference to a recognizer plug-in
factory to add to the list of registered recognizers
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot be
allocated for vector holding the plug-in factory pointers
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus
RegisterPlugin(PVMFRecognizerPluginFactory& aPluginFactory);
/**
注销某一种格式,将某一种识别的信息从注册信息列表中剔除
* This static method removes the
specified recognizer plug-in factory from the list of available
recognizers.
* The passed-in plug-in factory must
have been added before with RegisterPlugin() for this method to succeed.
* After the plug-in factory is
successfully removed, the factory instance can be deleted.
*
* @param aPluginFactory
*
A reference to a recognizer plug-in
factory to remove from the list of registered recognizers
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus
RemovePlugin(PVMFRecognizerPluginFactory& aPluginFactory);
/**
* This static method creates a recognition
session with the recognizer framework.
*
创建一个识别的会话,
* @param aSessionId
返回一个会话的
ID
*
A reference to a PVMFSessionId which
will be set to the session's unique identifier when this method
*
completes successfully.
* @param aCmdHandler
给它一个识别的观察者,也就是消息的监控者
*
A reference to a
PVMFRecognizerCommmandHandler which will receive asynchronous command
completion notification.
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus OpenSession(PVMFSessionId&
aSessionId, PVMFRecognizerCommmandHandler& aCmdHandler);
/**
* This static method shuts down a
recognition session with the recognizer framework.
*
关闭一个会话
* @param aSessionId
*
The unique identifier of the session to
close
*
* @returns A PVMF status code to
report result of method
**/
OSCL_IMPORT_REF static PVMFStatus CloseSession(PVMFSessionId
aSessionId);
/**
开始识别,开始识别的开始就需要一个数据的来源、然后是优先考虑的格
式、识别结果的存储、
* This static method asynchronously
determines the format of the specified content using the currently
registered
* recognizer plug-ins. When the
recognizer request completes, the user would be notified via the
PVMFRecognizerCommandHandler
* callback handler set when opening
the session.
*
* @param aSessionId
*
The unique identifier for the
recognizer session
* @param aSourceDataStreamFactory
数据的来源
*
A reference to a PVMFDataStreamFactory
representing the content to recognize
* @param aFormatHintList
优先考虑的格式
*
An optional input parameter expressed
as a list of MIME string which provides a priori hint for the format
*
of the content specified by
aSourceDataStreamFactory.
* @param aRecognizerResult
结果的存储
*
An output parameter which is a
reference to a vector of PVMFRecognizerResult that will contain the
recognition
*
result if the Recognize()
method succeeds.
* @param aCmdContext
*
Optional pointer to opaque data that
will be returned in the command completion response
,识别上下文的返回
* @param aTimeout
识别的时间限制
*
Optional timeout value for the
recognition request. If the recognition operation takes more time than
the
timeout
*
value, the operation will be cancelled
with PVMFErrTimeout status code. If the timeout value is set to 0, the
*
recognition operation will go to
completion.
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot
allocated to process this request
*
OsclErrArgument if one or more of the
passed-in parameters is invalid
*
* @returns A PVMF command ID for the
recognize request
**/
OSCL_IMPORT_REF static PVMFCommandId Recognize(PVMFSessionId
aSessionId,
PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHintList,
Oscl_Vector<PVMFRecognizerResult, OsclMemAllocator>&
aRecognizerResult, OsclAny* aCmdContext = NULL, uint32 aTimeout = 0);
/**
取消前一个异步的识别操作
* This static method cancels a
previously issued asynchronous request that hasn't completed yet.
*
* @param aSessionId
*
The unique identifier for the
recognizer session
* @param aCommandToCancelId
*
Unique identifier for the asynchronous
request to cancel.
* @param aCmdContext
*
Optional pointer to opaque data that
will be returned in the command completion response
*
* @exception This method can leave
with one of the following error codes
*
OsclErrNoMemory if memory cannot
allocated to process this request
*
OsclErrArgument if one or more of the
passed-in parameters is invalid
*
* @returns A PVMF command ID for the
cancel request
**/
OSCL_IMPORT_REF static PVMFCommandId CancelCommand(PVMFSessionId
aSessionId, PVMFCommandId aCommandToCancelId, OsclAny* aCmdContext =
NULL);
};
这样我们的识
别文件格式的框架就完成了。下面看一些具体的实现。
很遗憾,在
OSDL
中,我们已经定义好了一个类似于微软注册表的东西,它存在与
OSDL
中,在
OSDL
之上的任何代码都是可以访问的。
class
OsclTLSRegistry
{
public:
/*
** Get an entry
** @param ID: identifier
** @param error (output) 0 for success
or an error from TPVBasePanicEnum
** @returns: the entry value
*/
OSCL_IMPORT_REF static OsclAny*
getInstance(uint32 ID, int32 &error);
/*
** Set an entry
** @param ID: identifier
** @param error (output) 0 for success
or an error from TPVBasePanicEnum
** @returns: the entry value
*/
OSCL_IMPORT_REF static void
registerInstance(OsclAny* ptr, uint32 ID, int32 &error);
private:
OsclTLSRegistry()
{}
typedef OsclAny* registry_type;
typedef registry_type*
registry_pointer_type;
#if (
OSCL_TLS_IS_KEYED)
class TKeyItem
{
public:
TKeyItem(): iTlsKey(NULL),
iThreadId(0)
{}
TOsclTlsKey *iTlsKey;
TOsclTlsThreadId iThreadId;
};
class TlsKeyTable
{
public:
TlsKeyTable(): iNumKeys(0)
{}
_OsclBasicLock iLock;
uint32 iNumKeys;
TKeyItem iKeys[OSCL_TLS_MAX_THREADS];
};
//The key table is a global variable.
static TlsKeyTable* iTlsKeyTable;
static void
GetThreadId(TOsclTlsThreadId &threadId, int32&);
static TOsclTlsKey*
LookupTlsKey(int32&);
static bool SaveTlsKey(TOsclTlsKey*
key, int32&);
static bool
RemoveTlsKey(Oscl_DefAlloc& alloc, TOsclTlsKey* key, int32&);
#endif
private:
OSCL_IMPORT_REF static void
initialize(Oscl_DefAlloc &alloc, int32 &error);
OSCL_IMPORT_REF static void cleanup(Oscl_DefAlloc
&alloc, int32 &error);
friend class OsclBase;
};
这个类的实现
可以参见具体的代码,所以这里我们就不去多说。这里我们在注册信息中填入的是一个什么呢?
我们看静态的
初始化函数。
OSCL_EXPORT_REF PVMFStatus
PVMFRecognizerRegistry::Init()
{
// Check that there is no existing registry
PVMFRecognizerRegistryImpl*
pvrecregimpl
= OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
//
如果存在,那么我就不用注册这个一项了
if (pvrecregimpl != NULL)
{
// Registry is already present so no need to instantiate again
// Just increment the refcount
(pvrecregimpl->iRefCount)++;
return PVMFSuccess;
}
// Instantiate the
registry implementation
,否则就开始分配新的空间开始注册
Oscl_TAlloc<PVMFRecognizerRegistryImpl, OsclMemAllocator>
talloc;
pvrecregimpl = OSCL_ALLOC_NEW(talloc, PVMFRecognizerRegistryImpl,
());
// Save it on singleton or TLS
PVMFRECOGNIZER_REGISTRY::registerInstance(pvrecregimpl,
PVMFRECOGNIZER_REGISTRY_ID);
return PVMFSuccess;
}
继续往下面讲之前,我觉得我们可以看一下
PVMFRecognizerRegistryImpl
,这个是怎么实现的,
PVMFRecognizerRegistryImpl
是我们注册表中保存的一个东东。主要实现文件的识别,包含很多的信息。我以前以为只有变量才能注册
的,其实函数也能注册的,函数代码的空间也是数据,是数据就有指针,所以整个类也是可以注册的。注册后,如果要清空,那么就要调用
Cleanup
,
OSCL_EXPORT_REF void
PVMFRecognizerRegistry::Cleanup()
{
// Retrieve the registry implementation instance
from
singleton or TLS and destroy it
首先单件模式,返回我们注册的
PVMFRecognizerRegistryImpl
指针,这个指针指向的内容是存在的,因为我们前面在初始化的时候就分
配了内存
PVMFRecognizerRegistryImpl* pvrecregimpl =
OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
if (pvrecregimpl != NULL)
{
// First decrement
the refcount
,
直接自减就行了,自身负责分配
--(pvrecregimpl->iRefCount);
// If
the resulting refcount is 0, then delete the instance
if ((pvrecregimpl->iRefCount) <= 0)
{
Oscl_TAlloc<PVMFRecognizerRegistryImpl, OsclMemAllocator>
talloc;
OSCL_ALLOC_DELETE(pvrecregimpl, talloc,
PVMFRecognizerRegistryImpl);
// Unregister by putting NULL pointer
in
singleton or TLS
释放后,注意把注册表中的信息清空
PVMFRECOGNIZER_REGISTRY::registerInstance(NULL,
PVMFRECOGNIZER_REGISTRY_ID);
}
}
else
{
// Registry has already been cleaned up so nothing to do
}
}
然后就是注册我们的文件识别组件
OSCL_EXPORT_REF PVMFStatus
PVMFRecognizerRegistry::RegisterPlugin(PVMFRecognizerPluginFactory&
aPluginFactory)
{
PVMFRecognizerRegistryImpl* pvrecregimpl =
OSCL_STATIC_CAST(PVMFRecognizerRegistryImpl*,
PVMFRECOGNIZER_REGISTRY::getInstance(PVMFRECOGNIZER_REGISTRY_ID));
if (pvrecregimpl != NULL)
{
return
pvrecregimpl->RegisterPlugin(aPluginFactory);
}
else
{
// Registry hasn't been initialized yet. Assert
OSCL_ASSERT(false);
return PVMFErrNotReady;
}
}
其实很简单,调用对应的成员就行了。
下面的几个函数基本上都是这样子了,
RemovePlugin
、
OpenSession
、
CloseSession
、
Recognize
、
CancelCommand
。
下面我们看看
PVMFRecognizerRegistryImpl
的实现。
因为文件的识别是一个比较“卡”的过程,为
了不让我们的软件给人很卡的感官,我们这里把这个类另辟一个线程来进行,并且以异步的方式来调用,通过命令。
识别的命令有下面的两种类型:
/**
*
PVMFRecRegImplCommandType enum
*
*
Enumeration of commands that can be issued to the PVMF Recognizer
Registry
*
**/
typedef enum
{
PVMFRECREG_COMMAND_RECOGNIZE = 1,
PVMFRECREG_COMMAND_CANCELCOMMAND,
} PVMFRecRegImplCommandType;
一个就是开始识别,一个就是取消识别。
class PVMFRecRegSessionInfo
{
public:
PVMFRecRegSessionInfo()
{
};
PVMFRecRegSessionInfo(const PVMFRecRegSessionInfo& aSrc)
{
iRecRegSessionId = aSrc.iRecRegSessionId;
iRecRegCmdHandler = aSrc.iRecRegCmdHandler;
};
~PVMFRecRegSessionInfo()
{
};
PVMFSessionId iRecRegSessionId;
PVMFRecognizerCommmandHandler* iRecRegCmdHandler;
};
识别的一个信
息的保存,一个事识别的
sessionID
,一个事事件处理。
下面就是一个
命令的具体的封装,包含一个参数的列表
/**
*
PVMFRecRegImplCommand Class
*
*
PVMFRecRegImplCommand class is a data class
to hold issued commands inside the recognizer registry impl
**/
class PVMFRecRegImplCommand
{
public:
/**
* The constructor for
PVMFRecRegImplCommand which allows the data values to be set.
*
* @param aCmdType The command type
value for this command.
* @param aCmdId The command ID
assigned for this command.
* @param aContextData The pointer to
the passed-in context data for this command.
* @param aParamVector The optional pointer to a list of
parameters
*
* @returns None
**/
初始化就是一个参数
列表
PVMFRecRegImplCommand(PVMFSessionId aSessionId, int32 aCmdType,
PVMFCommandId aCmdId, OsclAny* aContextData = NULL,
Oscl_Vector<PVMFRecRegImplCommandParamUnion,
OsclMemAllocator>*
aParamVector = NULL, bool aAPICommand = true) :
iSessionId(aSessionId),
iCmdType(aCmdType),
iCmdId(aCmdId), iContextData(aContextData), iAPICommand(aAPICommand)
{
iParamVector.clear();
if (aParamVector)
{
iParamVector
= *aParamVector;
}
}
/**
* The copy constructor for
PVMFRecRegImplCommand. Used mainly for Oscl_Vector.
*
* @param aCmd The reference to the
source PVMFRecRegImplCommand to copy the data values from.
*
* @returns None
**/
PVMFRecRegImplCommand(const PVMFRecRegImplCommand& aCmd)
{
iSessionId = aCmd.iSessionId;
iCmdType = aCmd.iCmdType;
iCmdId = aCmd.iCmdId;
iContextData = aCmd.iContextData;
iAPICommand = aCmd.iAPICommand;
iParamVector = aCmd.iParamVector;
}
/**
* This function returns the session ID
for the command
*
* @returns The session ID value for
this command.
**/
PVMFSessionId GetSessionId()const
{
return iSessionId;
}
/**
* This function returns the stored
command type value.
*
* @returns The signed 32-bit command
type value for this command.
**/
int32 GetCmdType()const
{
return iCmdType;
}
/**
* This function returns the stored
command ID value.
*
* @returns The PVMFCommandId value for
this command.
**/
PVMFCommandId GetCmdId()const
{
return iCmdId;
}
/**
* This function returns the stored
context data pointer.
*
* @returns The pointer to the context
data for this command
**/
OsclAny* GetContext()const
{
return iContextData;
}
/**
* This function tells whether the
command is an API command or not
*
* @returns true if API command, false
if not.
**/
bool IsAPICommand()const
{
return iAPICommand;
}
/**
* This function returns the command
parameter from the specified index.
* If the specified index is not
available, empty parameter will be returned
*
* @param aIndex The index of the
parameter to return
*
* @returns The stored parameter for
this command
**/
PVMFRecRegImplCommandParamUnion GetParam(uint32 aIndex)const
{
if (aIndex >= iParamVector.size())
{
PVMFRecRegImplCommandParamUnion
param;
oscl_memset(¶m,
0,
sizeof(PVMFRecRegImplCommandParamUnion));
return
param;
}
else
{
return
iParamVector[aIndex];
}
}
bool operator==(const PVMFRecRegImplCommand& x)const
{
return iCmdId == x.iCmdId;
}
PVMFSessionId iSessionId;
int32 iCmdType;
PVMFCommandId iCmdId;
OsclAny* iContextData;
bool iAPICommand;
Oscl_Vector<PVMFRecRegImplCommandParamUnion,
OsclMemAllocator> iParamVector;
};
上面就是一个带参数的识别命令。
然后有一个优先级的比较:
class
PVMFRecRegImplCommandCompareLess
{
public:
/**
* The algorithm used in
OsclPriorityQueue needs a compare function
*
that returns true when A's priority is less than B's
* @return true if A's priority is less
than B's, else false
*/
int compare(PVMFRecRegImplCommand& a,
PVMFRecRegImplCommand& b)
const
{
int a_pri = PVMFRecRegImplCommandCompareLess::GetPriority(a);
int b_pri = PVMFRecRegImplCommandCompareLess::GetPriority(b);
if (a_pri < b_pri)
{
//
Higher priority
return
true;
}
else if (a_pri == b_pri)
{
//
Same priority so look at the
command ID to maintain FIFO
return
(a.GetCmdId() >
b.GetCmdId());
}
else
{
//
Lower priority
return false;
}
}
/**
* Returns the priority of each command
* @return A 0-based priority number. A
lower number indicates lower priority.
*/
static int GetPriority(PVMFRecRegImplCommand& aCmd)
{
switch (aCmd.GetCmdType())
{
case
PVMFRECREG_COMMAND_RECOGNIZE:
return
5;
case
PVMFRECREG_COMMAND_CANCELCOMMAND:
return
3;
default:
return
0;
}
}
};
如何识别的?
/**
* Implementation of the recognizer registry.
The recognizer interface class should only
* use this class.
**/
这里为什么要
从
PvmiDataStreamObserver
来继承,因为我们的识别就必须读取一部分的字节,必然会有相关的
data
数据流的操作,这里是一个简单的事件监控。为什么要从
OsclTimerObject
,因为我们识别是单开线程的,并且识别有一个时间的上线。
class
PVMFRecognizerRegistryImpl : public OsclTimerObject,
public PvmiDataStreamObserver
{
public:
PVMFRecognizerRegistryImpl();
~PVMFRecognizerRegistryImpl();
注册和注销识
别插件
PVMFStatus
RegisterPlugin(PVMFRecognizerPluginFactory& aPluginFactory);
PVMFStatus
RemovePlugin(PVMFRecognizerPluginFactory& aPluginFactory);
PVMFStatus
OpenSession(PVMFSessionId& aSessionId,
PVMFRecognizerCommmandHandler&
aCmdHandler);
PVMFStatus CloseSession(PVMFSessionId
aSessionId);
识别
PVMFCommandId Recognize(PVMFSessionId
aSessionId, PVMFDataStreamFactory& aSourceDataStreamFactory,
PVMFRecognizerMIMEStringList* aFormatHint,
Oscl_Vector<PVMFRecognizerResult,
OsclMemAllocator>&
aRecognizerResult, OsclAny* aCmdContext, uint32
aTimeout);
PVMFCommandId
CancelCommand(PVMFSessionId aSessionId, PVMFCommandId
aCommandToCancelId,
OsclAny* aCmdContext);
// Reference count for the registry
implementation
int32 iRefCount;
注册的
Plug
个数
private:
这个我怀疑是这样的,同时可能有多个识别的操作,那么就需要列表处理
PVMFSessionId iNextSessionId;
PVMFCommandId iNextCommandId;
// From OsclTimerObject
void Run();
// Vector to hold the active sessions
Oscl_Vector<PVMFRecRegSessionInfo,
OsclMemAllocator> iRecognizerSessionList;
// Vector to hold the available
recognizer plug-in
Oscl_Vector<PVMFRecognizerPluginFactory*, OsclMemAllocator>
iRecognizerPluginFactoryList;
int32
FindPluginFactory(PVMFRecognizerPluginFactory& aFactory);
PVMFRecognizerPluginInterface*
CreateRecognizerPlugin(PVMFRecognizerPluginFactory& aFactory);
void
DestroyRecognizerPlugin(PVMFRecognizerPluginFactory& aFactory,
PVMFRecognizerPluginInterface* aPlugin);
// Vector to hold pending, current,
and
to-cancel commands
OsclPriorityQueue<PVMFRecRegImplCommand, OsclMemAllocator,
Oscl_Vector<PVMFRecRegImplCommand, OsclMemAllocator>,
PVMFRecRegImplCommandCompareLess>
iRecognizerPendingCmdList;
Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator> iRecognizerCurrentCmd;
Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator> iRecognizerCmdToCancel;
PVMFCommandId
AddRecRegCommand(PVMFSessionId
aSessionId, int32 aCmdType, OsclAny* aContextData = NULL,
Oscl_Vector<PVMFRecRegImplCommandParamUnion, OsclMemAllocator>*
aParamVector = NULL, bool aAPICommand = true);
void
CompleteCurrentRecRegCommand(PVMFStatus aStatus, const uint32
aCurrCmdIndex =
0, PVInterface* aExtInterface = NULL);
bool
FindCommandByID(Oscl_Vector<PVMFRecRegImplCommand,
OsclMemAllocator>
&aCmdQueue, const PVMFCommandId aCmdId);
// Command handling functions
void DoRecognize();
void CompleteRecognize(PVMFStatus
aStatus);
void
DoCancelCommand(PVMFRecRegImplCommand& aCmd);
PVMFDataStreamFactory*
iDataStreamFactory;
PVMIDataStreamSyncInterface*
iDataStream;
PvmiDataStreamSession
iDataStreamSessionID;
PvmiDataStreamCommandId
iRequestReadCapacityNotificationID;
PVMFStatus
GetMaxRequiredSizeForRecognition(uint32& aMaxSize);
PVMFStatus
GetMinRequiredSizeForRecognition(uint32& aMinSize);
PVMFStatus CheckForDataAvailability();
//logger
PVLogger* iLogger;
/* From PvmiDataStreamObserver */
void DataStreamCommandCompleted(const
PVMFCmdResp& aResponse);
void
DataStreamInformationalEvent(const
PVMFAsyncEvent& aEvent);
void DataStreamErrorEvent(const
PVMFAsyncEvent& aEvent);
bool oRecognizePending;
PVMFStatus iDataStreamCallBackStatus;
};
这个函数具体是如何实现的,有兴趣的可以继续看一下,我小看了一下,基本上就是一个
for
循环识别文件的格式。并且这种框架
很容易扩展新的文件格式。不错不错。具体的文件
plug
怎么写,后面继续。
相关文章推荐
- c#读取并修改App.config文件实例(转载:http://blog.csdn.net/abuhome/archive/2010/01/13/5184467.aspx)
- 如何将Web应用打包成.war文件? 转自:http://blog.csdn.net/code_JAVA/archive/2008/05/19/2457749.aspx
- http://blog.csdn.net/KBUG/archive/2006/10/30/1357009.aspx
- 用开源组件jcaptcha做jsp彩色验证码 ( 转http://blog.csdn.net/alexjjf/archive/2006/10/31/1359333.aspx)
- Invalid postback or callback argument. (转http://blog.csdn.net/Alionkun/archive/2009/11/22/4853437.aspx)
- WPF体验(3) http://blog.csdn.net/niwalker/archive/2005/12/11/549146.aspx
- PE文件导入表的代码注入http://blog.csdn.net/xieqidong/archive/2008/05/05/2391338.aspx
- ubuntu找不到上下边栏(面板) -- ubuntu gnome panel lost has recovered 转自:http://blog.csdn.net/yangxinle137/archive/2010/09/26/5908225.aspx
- Android应用程序使用Google Map (转http://blog.csdn.net/iefreer/archive/2009/09/20/4572879.aspx)
- http://blog.csdn.net/ol_beta/archive/2010/10/27/5968817.aspx
- HttpClient入门教程(zz)http://blog.csdn.net/cocojiji5/archive/2008/10/10/3048695.aspx
- http://blog.csdn.net/CYRTSOFT/archive/2004/12.aspx
- 动态连接库入门(转载自光头的学习文档http://blog.csdn.net/yuguanglou/archive/2004/11/10/175879.aspx)
- 使用CSS3构建Ajax加载动画(转http://blog.csdn.net/hfahe/archive/2011/02/10/6177825.aspx)
- auto_ptr作用和用法(转:http://blog.csdn.net/danforn/archive/2008/06/30/2598413.aspx)
- ASP.net输出JS脚步的类(无AJAX框架)(原作者发布地址http://blog.csdn.net/zhoufoxcn/archive/2008/04/21/2312440.aspx)
- 资料(http://blog.csdn.net/bogues/archive/2005/11/22/534982.aspx)
- window.event(转自:http://blog.csdn.net/cnkiminzhuhu/archive/2008/02/22/2112408.aspx)
- 字符编码的奥秘(转自http://blog.csdn.net/hbrqlpf/archive/2007/09/24/1798935.aspx)
- SQL Server的相关注册表项使用技巧六则(转http://blog.csdn.net/billpu/archive/2010/09/27/5909937.aspx)