TCPMP源代码分析
来源:互联网 发布:java自学看什么书 编辑:程序博客网 时间:2024/06/11 11:13
播放器主要由核心框架模块( common 工程)和解码器、分离器插件组成。 TCPMP 的插件非常多,其中主要的插件有: interface 插件实现了 TCPMP 的界面, ffmpeg 是系统主要的音视频解码模块, splitter 是媒体文件分离器。
由于 ffmpeg 的解码效率不高,系统仅使用了 ffmpeg 的部分功能。并且未使用其中的 libavformat 模块,而使用 splitter 模块进行。其他插件暂时没有研究。本周主要分析的是 common 工程。
common 工程是核心模块,是一个开放的集数据输入、转换、音 / 视频解码、信号输出等功能为一体的完整的多媒体播放框架。这个框架自身不包含任何的 Decode 和 Split 功能,这些功能由插件实现,核心模块以一个树状结构管理所有的功能模块和插件模块,实现数据 Render 功能,对输入、转换、输出流程的控制,接受播放过程中的操作和对事件进行处理,同时也实现系统运行中经常使用的一些共用函数,比如解码过程中经常使用的逆离散余弦变换,内存操作,界面中需要使用的多语言字符处理等。
common 工程的主目录下主要有: blit 、 dyncode 、 overlay 、 pcm 、 softidct 、 win32 、 zlib 等子目录。其中 blit 和 overlay 存放是视频信号渲染模块, pcm 存放 PCM 音频信号转换模块, softidct 存放逆离散余弦变换函数, win32 存放内存操作等常用模块, dyncode 这个目录的代码比较晦涩,存放的是程序运行时动态生成代码模块,针对不同的 CPU 指令集, PCM 数据声道和采样率不同,视频渲染数据格式和色深等不同情况动态生成不同的优化代码, zlib 则提供了内存中压缩和解压缩的函数 , 包括未压缩数据的完整性检查。
以下是 common 工程核心模块中几个重要的概念:
( 1 )上下文对象 context
该对象在初始化函数 bool_t Context_Init中创建了一个该对象实例( context.h)。该对象实例记录管理各个功能模块,用户界面可以通过该对象和核心模块交互,管理控制播放过程。
( 2 )功能模块
功能模块包括定义对象 nodedef 和数据对象 node ,定义对象描述功能模块相互间的逻辑结构,数据对象记录模块属性和方法。所有的功能模块结构按一个树状结构来组织,结构关系如下, NODE 是整个结构的根结点,其下为子节点,节点按类型可分为 实节点 , 全局节点 , 设置节点 , 抽象节点 。
抽象节点没有对应的对象实例,类似 C++ 的抽象基类,为了按照逻辑关系组织系统结构而存在,例如 NODE 就是抽象节点。全局节点只有一个对象的实例,如播放控制模块 PLAYER_ID 。设置节点表示和系统播放设置相关,比如声音均衡器模块 EQUALIZER_ID ,颜色控制模块 COLOR_ID 。实节点与抽象节点不同,指可以生成对象实例的节点,实节点没有特殊标识,一般以数据对象占用内存大小表示是否是一个实节点,创建节点时要根据该信息分配内存单元,实节点也可以有子节点,例如: MMS_ID 的父节点是 HTTP_ID 。全局节点,设置节点和实节点可以相互组合,比如播放控制节点同时是全局节点,设置节点和实节点。
下面是主要的节点树状分布图:
NODE (根节点)
├─ FLOW (流控制模块)
│ ├─ CODEC (解码模块)
│ │ ├─ EQUALIZER_ID (声音均衡器模块)
│ │ ├─ VBUFFER_ID (视频缓冲模块)
│ │ ├─ DMO ( DirectX Media Object )
│ │ │ ├─ WMV_ID
│ │ │ ├─ WMS_ID
│ │ │ ├─ WMVA_ID
│ │ │ ├─ WMA_ID
│ │ │ └─ WMAV_ID
│ │ ├─ FFMPEG VIDEO ( FFMpeg 解码模块)
│ │ └─ LIBMAD_ID ( Libmad Mp3 解码模块)
│ ├─ OUT (信号渲染模块)
│ │ ├─ AOUT (音频信号渲染)
│ │ │ ├─ NULLAUDIO_ID
│ │ │ └─ WAVEOUT_ID
│ │ └─ VOUT (视频信号渲染)
│ │ ├─ NULLVIDEO_ID
│ │ └─ OVERLAY
│ ├─ IDCT (离散余弦解码模块)
│ │ └─ SOFTIDCT_ID
│ └─ CODECIDCT (离散余弦解码模块,函数比 IDCT 要少)
│ └─ MPEG1_ID
├─ MEDIA (媒体文件格式编码解析模块)
│ ├─ FORMAT (格式解析模块)
│ │ └─ FORMATBASE
│ │ ├─ RAWAUDIO
│ │ │ └─ MP3_ID
│ │ ├─ RAWIMAGE
│ │ ├─ ASF_ID
│ │ ├─ AVI_ID
│ │ ├─ MP4_ID
│ │ ├─ MPG_ID
│ │ ├─ NSV_ID
│ │ └─ WAV_ID
│ ├─ PLAYLIST (播放列表模块)
│ │ ├─ ASX_ID
│ │ ├─ M3U_ID
│ │ └─ PLS_ID
│ └─ STREAMPROCESS (数据流处理模块)
├─ STREAM (数据输入模块)
│ ├─ MEMSTREAM_ID (内存数据流模块)
│ ├─ FILE_ID (文件 IO 模块)
│ └─ HTTP_ID (网络数据获取模块)
├─ TIMER (定时器模块)
│ └─ SYSTIMER_ID
├─ ASSOCIATION_ID (文件扩展名自动关联模块)
├─ ADVANCED_ID (高级设置模块)
├─ COLOR_ID (颜色控制模块)
├─ PLATFORM_ID (平台信息模块)
├─ XSCALEDRIVER_ID
├─ PLAYER_ID (播放控制模块)
└─ PLAYER_BUFFER_ID (播放缓冲模块)
以下是 common 工程核心模块的几个重要数据结构:
( 1 ) context 上下文对象
typedef struct context
{
int Version;// 版本信息
uint32_t ProgramId;// 应用程序句柄
const tchar_t* ProgramName;// 应用程序名称
const tchar_t* ProgramVersion;// 程序版本号 , 字符串
const tchar_t* CmdLine;// 程序命令行信息
void* Wnd;// 视频渲染窗口句柄
void* NodeLock;// 功能模块访问临界区互斥变量
array Node; // 功能模块数据对象数组
array NodeClass; // ordered by id 功能模块定义对象数组 , 按照系统逻辑关系组织
array NodeClassPri; // ordered by priority|id 功能模块定义对象数组 , 按照系统逻辑关系和优先级排列
array NodeModule;// 外部插件模块数组
int LoadModuleNo;// 当前正在加载的外部插件序号
void* LoadModule;// 当前正在加载的外部插件
array StrTable[2];// 字符串资源数组 , 字符串分为:给底层使用的标准字符串资源、给界面使用的显示字符串资源 , 两个资源用两个数组表示
array StrBuffer;
array StrModule;// 未使用
void* StrLock;// 字符串数组访问临界区互斥变量
uint32_t Lang;// 当前使用语言标志
int CodePage;// 当前使用代码页标志
struct pcm_soft* PCM;//PCM 音频信号转换模块
struct blitpack* Blit;// 视频信号渲染模块
struct node* Platform;// 得到平台相关信息
struct node* Advanced;// 得到播放模块高级信息
struct node* Player;// 播放控制模块
notify Error;// 信息错误回调函数
int (*HwOrientation)(void*);
void *HwOrientationContext;
bool_t TryDynamic;// 未使用
int SettingsPage;// 未使用
size_t StartUpMemory;// 可以使用的有效内存数
bool_t InHibernate;// 是否进入休眠状态
bool_t WaitDisable;// 未使用
int FtrId;// 未使用
bool_t LowMemory;// 可以使用的有效内存数是否小于系统要求的最低要求
// 动态代码生成中间状态及数据
bool_t CodeFailed;
bool_t CodeMoveBack;
bool_t CodeDelaySlot;
void* CodeLock;
void* CodeInstBegin;
void* CodeInstEnd;
int NextCond;
bool_t NextSet;
bool_t NextByte;
bool_t NextHalf;
bool_t NextSign;
uint32_t* FlushCache;// 未使用
void* CharConvertUTF8;// 未使用
void* CharConvertCustom;// 未使用
int CustomCodePage;// 未使用
void* CharConvertAscii;// 未使用
void* Application;
void* Logger;// 未使用
bool_t KeepDisplay;// 是否保持背光长亮
int DisableOutOfMemory;// 未使用
} context;
( 2 ) nodedef 功能模块定义对象
功能模块树状结构通常由若干个静态定义对象 (nodedef) 实例实现,
typedef struct nodedef
{
int Flags;// 功能模块节点的类型:抽象、实节点、全局、设置。
int Class;// 功能模块节点的标识,如 MEDIA_CLASS 或 ASF_ID 等等。
int ParentClass;// 功能模块父节点的标识,如 SYSTIMER_ID 对象的父节点是 TIMER_CLASS 。
int Priority;// 表示功能模块节点优先级。
nodecreate Create;// 创建功能模块定义对象的函数指针
nodedelete Delete;// 销毁功能模块定义对象的函数指针
} nodedef;// 功能模块定义对象
如解码器功能模块静态定义对象:
static const nodedef Codec =
{
sizeof(codec)|CF_ABSTRACT,
CODEC_CLASS,
FLOW_CLASS,
PRI_DEFAULT,
(nodecreate)Create,
(nodedelete)Delete,
};
( 3 ) nodeclass 功能模块定义对象链表结构
用链表的方式实现了功能模块树状结构,每个链表代表树状结构的一个分支。
typedef struct nodeclass
{
nodedef Def;// 功能模块定义对象
bool_t Registered;// 是否注册
int ModuleNo;// 模块标识
struct nodeclass* Parent;// 功能模块定义对象的父对象
} nodeclass;// 功能模块定义节点对象链表结构
( 4 ) node 功能模块数据对象
typedef struct node
{
int Class;// 功能模块节点的类型 , 如 MEDIA_CLASS 等等,与 nodedef 相同。
nodeenum Enum;// 枚举节点属性函数指针
nodeget Get;// 获取节点属性的函数指针
nodeset Set;// 设置节点属性的函数指针
} node;// 功能模块数据对象
上述几个数据对象的相互关系:
在系统上下文对象 context 中有两个元素记录功能模块信息 array Node 和 array NodeClass , array 是数组数据类型(在 buffer.h/c 中定义和实现), Node 是功能模块数据对象的数组, NodeClass 功能模块定义对象的数组,按照系统逻辑关系组织。
创建功能模块时传入 nodedef 对象到功能模块创建函数,函数会根据 nodedef 信息生成对应 nodeclass 对象添加到 NodeClass 数组,同时根据 nodedef 信息分配数据对象的内存空间。在该节点的 Create 函数里面再初始化该功能模块的数据对象 node 。
( 5 ) datadef 功能模块属性
typedef struct datadef
{
int No;// 属性的标识,如播放控制模块的 #define PLAYER_PLAY 0x32 就表示控制播放器播放或暂停。
int Type;// 属性的数据类型,在 node.h 中定义,如 TYPE_BOOL
int Flags;// 属性数据的标志,是属性数据的标志,表示该数据是不是只读数据,是否有最大最小值等等, node.h 中定义,如 DF_RDONLY
int Format1;
int Format2;
const tchar_t* Name;
int Class;
int Size;
} datadef;// 属性对象定义
其中 Format1 和 Format2 是可选标志与 Flags 配合使用,比如如果 Flags 表示该属性存在最大最小值, Format1 就是最大值, Format2 则是最小值;
另外,如果( !(Flags & DF_NOSAVE) && !(Flags & DF_RDONLY) )即属性标识为保存且可读写,则会被记录到注册表中,下次启动时用注册表的数据初始化该属性表。
( 6 ) datatable 功能模块属性列表
typedef struct datatable
{
int No;
int Type;
int Flags;
int Format1;
int Format2;
} datatable;// 功能模块属性列表
各功能模块的属性通常以数组的形式定义和存储,如格式解析模块属性列表
static const datatable Params[] =
{
{ FORMAT_INPUT, TYPE_NODE, DF_INPUT|DF_HIDDEN, STREAM_CLASS },
{ FORMAT_OUTPUT, TYPE_NODE, DF_HIDDEN, STREAM_CLASS },
{ FORMAT_DURATION, TYPE_TICK },
{ FORMAT_FILEPOS, TYPE_INT, DF_HIDDEN },
{ FORMAT_FILESIZE, TYPE_INT, DF_KBYTE },
{ FORMAT_AUTO_READSIZE, TYPE_BOOL, DF_HIDDEN },
{ FORMAT_GLOBAL_COMMENT,TYPE_COMMENT, DF_OUTPUT },
{ FORMAT_FIND_SUBTITLES,TYPE_BOOL, DF_HIDDEN },
{ FORMAT_STREAM_COUNT, TYPE_INT, DF_HIDDEN },
DATATABLE_END(FORMAT_CLASS)
};
( 7 ) nodemodule 外部插件功能模块
typedef struct nodemodule
{
int Id;// 插件标识
int ObjectCount;// 该插件的实例个数 ( 引用计数 )
bool_t Tmp;// 是否是临时节点
int64_t Date;// 设置时间
int KeepAlive;// 保持时间
void* Module;// 外部插件模块
void* Db;
void* Func;
uint8_t* Min;
uint8_t* Max;
} nodemodule;// 外部插件模块节点
核心模块的初始化流程及相应代码对应关系 ( 参考 context.c 中的 Context_Init 函数 )
Mem_Init();
// 内存等资源初始化( Win32/mem_win32.c )
DynCode_Init();
// 程序运行动态生成代码模块 , 优化 PCM, 视频渲染模块等 (DynCode/DynCode.c )
String_Init();
// 系统使用字符串初始化 (str.c,Win32/str_win32.c )
PCM_Init();
// 音频信号转换模块初始化 (PCM/pcm_soft.c )
Blit_Init();
// 视频信号渲染模块初始化 (Blit/blit_soft.c )
Node_Init();
// 根节点模块初始化 (node.c,Win32/node_win32.c )
Platform_Init();
// 平台信息模块初始化 (platform.c,Win32/platform_win32.c )
Stream_Init();
// 输入数据流模块初始化 (streams.c )
Advanced_Init();
// 高级设置模块初始化 (advance.c )
Flow_Init();
// 流控制模块初始化 (flow.c )
Codec_Init();
// 解码模块初始化 (codec.c )
Audio_Init();
// 音频信号处理模块初始化 (audio.c )
Video_Init();
// 视频信号处理模块初始化 (video.c )
Format_Init();
// 格式解析模块初始化 (format.c )
Playlist_Init();
// 播放列表模块初始化 (playlist.c )
FormatBase_Init();
// 基本格式解析模块初始化 (format_base.c,format_subtitle.c )
NullOutput_Init();
// 无输出设备模块初始化 (nulloutput.c )
RawAudio_Init();
//RawAudio 模块初始化 (rawaudio.c )
RawImage_Init();
//RawImage 模块初始化 (rawimage.c )
Timer_Init();
// 定时器模块初始化 (timer.c )
IDCT_Init();
// 离散余弦解码模块初始化 (idct.c )
Overlay_Init();
// 视频叠加模块初始化 (overlay.c )
M3U_Init();
//M3U 格式播放列表模块初始化 (PlayList/m3u.c )
PLS_Init();
//PLS 格式播放列表模块初始化 (PlayList/pls.c )
ASX_Init();
//ASX 格式播放列表模块初始化 (PlayList/asx.c )
WaveOut_Init();
// 波形输出模块初始化 (waveout.c,Win32/waveout_win32.c )
SoftIDCT_Init();
//soft 离散余弦解码模块初始化 (SoftIDCT/softidct.c )
Plugins_Init();
// 外部插件模块初始化( Win32/node_win32.c )
另外还有 文件扩展名自动关联模块 Association_Init ( 参考文件 Win32/ association_win32.c) ;颜色控制模块 Color_Init( 参考 color.c) ;声音均衡器模块 Equalizer_Init( 参考 equalizer.c) ;播放控制模块初始化 ( 参考 player.c ) 。
向系统中载入外部插件模块(参考 node.c 以及 node_win32.c )
node.c 中的 LoadModule 函数,可以在系统中载入外部插件模块,
static NOINLINE nodemodule* LoadModule(context* p,int No) ,
第一个参数是上下文对象,
第二个参数是外部插件模块标识
node_win32.c 定义了 dll 的载入与卸载函数以及相应的注册表操作,如
在功能模块节点载入外部插件模块
void* NodeLoadModule(const tchar_t* Path,int* Id,void** AnyFunc,void** Db)
与界面相交互的播放控制模块( player.c )
在所有功能模块中和界面加交互的主要就是播放控制模块 struct node* Player; 使用方法如下:
context* p = Context();
player* myplayer = NULL;
if(p) myplayer = (player*)(p->Player);
控制播放 使用
Set(void* This,int No,const void* Data,int Size)
第一个参数是播放模块指针,
第二个参数是控制代码,即要进行什么操作,
第三个参数是需要赋值给控制代码的数值,
最后一个参数是所赋数值的占用内存的大小。
myplayer->Set(myplayer,PLAYER_PLAY,1,sizeof(int));
PLAYER_PLAY 为控制代码,表示当前控制的是播放暂停功能,数值为 1 表 示播放为 0 表示暂停。
得到某一控制属性 使用 Get(void* This,int No,void* Data,int Size); 函数,参数含义和 Set 函数相同。
控制代码 是一组宏,定义在 player.h 文件中。比较重要的控制参数有播放控制模块所有可用参数见 static const datatable PlayerParams[] 结构。
添加一个媒体文件到播放模块 使用
int PlayerAdd(player* Player,int Index, const tchar_t* Path, const tchar_t* Title);
第一个参数为播放模块指针,
第二个参数是添加到播放模块文件队列的序号,如果是使文件成为第一个文 件该参数设为 0 ,
第三个参数是媒体文件的目录和名称,
第四个参数为媒体文件标题,该参数可以忽略。
- TCPMP源代码分析
- TCPMP源代码分析
- TCPMP源代码分析---窥豹一斑
- TCPMP源代码分析
- TCPMP源代码分析
- TCPMP 源代码分析1
- TCPMP 源代码分析2
- TCPMP源代码分析
- TCPMP源代码分析
- TCPMP源代码分析---窥豹一斑
- TCPMP源代码分析
- TCPMP源代码分析
- TCPMP源代码分析
- TCPMP源代码分析---窥豹一斑
- TCPMP源代码分析
- tcpmp 编译 源代码分析
- TCPMP源代码分析(二)
- TCPMP源代码编译
- ExecuteReader的用法
- FFMpeg框架代码阅读
- kiki's game
- My vim 配色文件
- 把数据库表的某一列的数据添加到comboBox中
- TCPMP源代码分析
- 经典学习网址
- TCPMP播放器UI的修改方法
- 如何使用google解决问题
- 图像处理2--打开多个摄像头
- WINCE TCPMP应用一:TCPMP概述
- iconv(3)
- MySQL 存储引擎简介
- WINCE TCPMP应用二: COMMON.DLL解析