TCPMP 原代碼分析2

播放器主要由核心框架模塊(common工程)和解碼器、分離器插件組成。TCPMP的插件非常多,其中主要的插件有:interface插件實現了TCPMP的界面,ffmpeg是系統主要的音視頻解碼模塊,splitter是媒體文件分離器。

由於ffmpeg的解碼效率不高,系統僅使用了ffmpeg的部分功能。並且未使用其中的libavformat模塊,而使用splitter模塊進行。其他插件暫時沒有研究。本週主要分析的是common工程。

common工程是核心模塊,是一個開放的集數據輸入、轉換、音/視頻解碼、信號輸出等功能爲一體的完整的多媒體播放框架。這個框架自身不包含任何的DecodeSplit功能,這些功能由插件實現,核心模塊以一個樹狀結構管理所有的功能模塊和插件模塊,實現數據Render功能,對輸入、轉換、輸出流程的控制,接受播放過程中的操作和對事件進行處理,同時也實現系統運行中經常使用的一些共用函數,比如解碼過程中經常使用的逆離散餘弦變換,內存操作,界面中需要使用的多語言字符處理等。

common工程的主目錄下主要有:blitdyncodeoverlaypcmsoftidctwin32zlib等子目錄。其中blitoverlay存放是視頻信號渲染模塊,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工程核心模塊的幾個重要數據結構:

1context 上下文對象

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;

2nodedef  功能模塊定義對象

功能模塊樹狀結構通常由若干個靜態定義對象(nodedef)實例實現,
typedef struct nodedef

{

        int     Flags;//功能模塊節點的類型:抽象、實節點、全局、設置。

        int     Class;//功能模塊節點的標識,如MEDIA_CLASSASF_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,

};

3nodeclass  功能模塊定義對象鏈表結構

用鏈表的方式實現了功能模塊樹狀結構,每個鏈表代表樹狀結構的一個分支。

typedef struct nodeclass

{

        nodedef Def;//功能模塊定義對象

        bool_t Registered;//是否註冊

        int ModuleNo;//模塊標識

        struct nodeclass* Parent;//功能模塊定義對象的父對象

 

} nodeclass;//功能模塊定義節點對象鏈表結構

4node  功能模塊數據對象

typedef struct node

{

        int                     Class;//功能模塊節點的類型,MEDIA_CLASS等等,與nodedef相同。

        nodeenum  Enum;//枚舉節點屬性函數指針

        nodeget             Get;//獲取節點屬性的函數指針

        nodeset             Set;//設置節點屬性的函數指針

 

} node;//功能模塊數據對象

 

上述幾個數據對象的相互關係:

        在系統上下文對象context中有兩個元素記錄功能模塊信息array Nodearray NodeClassarray是數組數據類型(在buffer.h/c中定義和實現),Node是功能模塊數據對象的數組,NodeClass功能模塊定義對象的數組,按照系統邏輯關係組織。

        創建功能模塊時傳入nodedef對象到功能模塊創建函數,函數會根據nodedef信息生成對應nodeclass對象添加到NodeClass數組,同時根據nodedef信息分配數據對象的內存空間。在該節點的Create函數裏面再初始化該功能模塊的數據對象node

 

5datadef 功能模塊屬性

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;//屬性對象定義

其中Format1Format2是可選標誌與Flags配合使用,比如如果Flags表示該屬性存在最大最小值,Format1就是最大值,Format2則是最小值;

另外,如果(!(Flags & DF_NOSAVE) && !(Flags & DF_RDONLY))即屬性標識爲保存且可讀寫,則會被記錄到註冊表中,下次啓動時用註冊表的數據初始化該屬性表。

 

6datatable  功能模塊屬性列表

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)

};

7nodemodule  外部插件功能模塊

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

        第三個參數是媒體文件的目錄和名稱,

        第四個參數爲媒體文件標題,該參數可以忽略。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章