TCPMP界面插件模块分析

TCPMP界面插件模块分析

一:界面模块主要节点结构

NODE (根节点)
    ├─WIN_CLASS[WIN_]
(界面抽象模块,负责全局窗口类注册)
    │  ├─QUERYKEY_ID[QKEY]
(未知模块)

│  ├─OPENFILE_ID [OPEN] (打开文件窗口的全局模块)

│  ├─INTERFACE_ID [INTF] (主播放窗口的全局设置模块,负责播控快捷键)

│  ├─PLAYLIST_ID [PLST] (播放列表窗口的全局模块)

│  ├─ABOUT_ID [ABOU] (关于窗口模块)

│  ├─BENCHRESULT_ID [BENC] (平台测试结果窗口模块)

│  ├─MEDIAINFO_ID [MEDI] (媒体信息窗口模块)

│  ├─SETTINGS_ID [SETU] (设置窗口模块)

二:界面模块消息分发流程

WinMain[player.exe]
    ├─Main [interface.plg]
    │  ├─Context_Init

│  ├─WinPopupClass(INTERFACE_ID)

│  │  ├─Popup

│  │  │  ├─CreateWindowEx
    │  │  │  ├─while (GetMessage(&Msg, NULL, 0, 0)) HandleMessage(p,&Msg);

│  │  │  │  ├─优先处理自定义Application Window消息以及按键消息

│  │  │  │  ├─调用DispatchMessage分发消息给窗口注册处理函数Proc

│  │  │  │  │  ├─Proc[win_win32.c]

│  │  │  │  │  │  ├─处理常见窗口消息

│  │  │  │  │  │  ├─调用窗口节点实例的处理函数Proc

│  │  │  │  │  │  │  ├─Proc[interface.c]

│  ├─Context_Done

三:界面模块创建流程分析

1. TCPMP创建主界面的入口函数位于interface.plg插件的stdafx.c源文件中,具体为Main函数调用的WinPopupClass函数。在正确调用Context_Init之后,TCPMP节点树结构已经创建出来,其中界面部分的节点结构是通过调用Plugins_Init()进而调用interface.plg的插件注册函数DLLRegister()完成。

DLLEXPORT void Main(const tchar_t* Name,const tchar_t* Version,int Id,const tchar_t* CmdLine)

{

       SAFE_BEGIN

       if (Context_Init(Name,Version,Id,CmdLine,NULL))

       {

              WaitEnd();

              WinPopupClass(INTERFACE_ID,NULL);

              Context_Done();

       }

       SAFE_END

}

 

2. WinPopupClass函数调用Popup函数,在Popup函数中将调用CreateWindowEx来创建具体的主窗口,然后进入消息处理循环体。

Wnd=CreateWindowEx(ExStyle,WinClass.lpszClassName,LangStr(p->Node.Class,NODE_NAME),Style,x,y,Width,Height, Parent?Parent->Wnd:NULL,NULL,WinClass.hInstance,p);

……

while (p->Wnd && GetMessage(&Msg, NULL, 0, 0))  HandleMessage(p,&Msg);

 

3. 主窗口收到的第一个消息是WM_CREATE,这将进入到主窗口的注册处理函数Proc[win_win32.c]

//触发MSG_PREPARE消息处理流程。主播放窗口的MSG_PREPARE流程为空。

if (p->Proc) p->Proc(p,MSG_PREPARE,0,0,&Result);

//创建窗口底部的菜单栏,调用WinCE API函数SHCreateMenuBar

CreateToolBar(p);

//调用interface_idProc过程。

if (p->Proc && p->Proc(p,Msg,wParam,lParam,&Result)) return Result;

 

4. interface.c文件的Proc函数WM_CREATE中,将完成一系列主要的初始化操作。

//设置窗口标题为程序名称

WinTitle(&p->Win,Context()->ProgramName);

//记录当前的播放控制模块指针

p->Player = (player*)Context()->Player;

//设置播放过程中的播放消息回调函数

Notify.This = p;

Notify.Func = (notifyfunc)PlayerNotify;

if (p->Player) p->Player->Set(p->Player,PLAYER_NOTIFY,&Notify,sizeof(Notify));

//设置播放过程中的播放出错回调函数

Context()->Error.This = p;

Context()->Error.Func = ErrorNotify;

//换肤功能,目前未实现

if (IsAutoRun(p,Context()->CmdLine))

       DefaultSkin(p);

SkinLoad(p->Skin,p->Win.Wnd,p->SkinPath);

//创建播放操作按钮(播放/暂停,停止,全屏,静音)

if (!p->Skin[0].Valid)

       CreateButtons(p);

UpdateSkin(p,0);

//创建播放进度条

UpdateTrackBar(p,0);

//创建播放标题栏

UpdateTitleBar(p,0);

//创建音量进度条

CreateVolumeTrack(p);

CreateDeviceMenu(p);

//主窗口绘制布局的最重要函数

Resize(p);

 

//发送MSG_INIT消息给自身,以进行后续的初始化工作。

// first finish window creation and postpone loading playlist and etc...

PostMessage(p->Win.Wnd,MSG_INIT,0,0);

 

5. interface.c文件的Proc函数MSG_INIT中,将完成一系列后续的初始化操作。

//设置主播放窗口为前置窗口

SetForegroundWindow(p->Win.Wnd);

//检查程序注册表项HKEY_LOCAL_MACHINE/Software/TCPMP/9216是否存在。如果存在,//则可认为上次程序为非正常退出。注:REG_INITING值为0x2400,十进制值即为9216

if (Context()->CmdLine[0] || NodeRegLoadValue(0,REG_INITING,&i,sizeof(i),TYPE_INT))

{

       b = 1; // last time crashed -> discard saved playlist

       p->Player->Set(p->Player,PLAYER_DISCARDLIST,&b,sizeof(b));

}

//写入程序注册表项HKEY_LOCAL_MACHINE/Software/TCPMP/9216,标识程序正在启动中。//然后启动定时器三秒后删除此项,在程序退出前调用BeforeExit()函数也会负责删除此项。

#ifdef NDEBUG

i = 1;

NodeRegSaveValue(0,REG_INITING,&i,sizeof(int),TYPE_INT);

SetTimer(p->Win.Wnd,TIMER_INITING,INITING_CYCLE,NULL);

#endif

 

//设置视频渲染窗口为当前窗口

Context_Wnd(p->Win.Wnd);

//检查程序是否携带参数运行,并且检查PLAYER_PLAYATOPEN_FULL参数。

//如果为0则表示不启用全屏播放。然后调用ProcessCmdLine进行后续参数处理。

if (Context()->CmdLine[0])

{

       p->Player->Get(p->Player,PLAYER_PLAYATOPEN_FULL,&b,sizeof(b));

       if (!b)

       {

              UpdateWindow(p->Win.Wnd); //http connection may take a while

              if (p->Win.WndTB) UpdateWindow(p->Win.WndTB);

       }

       ProcessCmdLine(p,Context()->CmdLine);

}

 

6. interface.c文件的ProcessCmdLine函数中,将完成程序参数的解析流程。

//检查参数是否为”-autorun”,如果为自动运行,则会枚举用户手机SD卡中的所有可识别的音视频介质,加入到播放列表中。否则将把参数作为普通的播放URL

if (IsAutoRun(p,CmdLine))

//把参数作为普通的播放URL,加入到播放列表中

n = 1;

p->Player->Set(p->Player,PLAYER_LIST_COUNT,&n,sizeof(n));

PlayerAdd(p->Player,0,URL,NULL);

//指定开始播放列表中的第1个介质文件。

n = 0;

p->Player->Set(p->Player,PLAYER_LIST_CURRIDX,&n,sizeof(n));

四:界面布局分析

界面布局的主要函数为interface.c文件中的Resize函数。

static void Resize(intface* p)

{

       //检查屏幕显示模式是否变化(横屏/竖屏)

       bool_t Rotated = IsOrientationChanged();

       if (Rotated)

       {

              //设置开始旋转

              p->Player->Set(p->Player,PLAYER_ROTATEBEGIN,NULL,0);

              //重置视频输出

              p->Player->Set(p->Player,PLAYER_RESETVIDEO,NULL,0);

              if (!p->Win.ToolBarHeight)

              {

                     p->VolResizeNeeded2 = 1; // toolbar position may change later

                     if (p->WndVolBack && IsWindowVisible(p->WndVolBack))

                     {

                            ShowVol(p,0);

                            p->VolResizeNeeded2 = 2;

                     }

              }

              else

                     p->VolResizeNeeded = 1;

 

              if (p->Win.FullScreen)

                     PostMessage(p->Win.Wnd,MSG_PLAYER,PLAYER_FULLSCREEN,0);

       }

 

       p->Offset.x = 0;

       p->Offset.y = 0;

       ClientToScreen(p->Win.Wnd,&p->Offset);

 

       if (!p->Win.FullScreen)

       {

#if !defined(TARGET_WINCE) && defined(MAXIMIZE_FULLSCREEN)

              WINDOWPLACEMENT Place;

              Place.length = sizeof(Place);

              GetWindowPlacement(p->Win.Wnd,&Place);

              if (Place.showCmd != SW_MAXIMIZE)

#endif

              {

                     GetClientRect(p->Win.Wnd,&r);

 

                     if (r.right != p->ClientRect.right || r.bottom != p->ClientRect.bottom)

                     {

                            bool_t Skin = p->Skin[p->SkinNo].Valid;

                            int TrackThumb;

                            int TrackHeight = 0;

                            p->TitleHeight = 0;

                            p->ClientRect = r;

 

                            r.top += p->Win.ToolBarHeight;

 

                            if (p->WndTrack)

                            {

                                   TrackHeight = WinUnitToPixelY(&p->Win,TRACKHEIGHT);

                                   r.bottom -= TrackHeight;

                                   MoveWindow(p->WndTrack,r.left,r.bottom,r.right,TrackHeight,TRUE);

 

                                   TrackThumb = WinUnitToPixelY(&p->Win,TRACKTHUMB);

                                   if (p->TrackThumb != TrackThumb)

                                   {

                                          p->TrackThumb = TrackThumb; // avoid calling this regulary because it shows the trackbar

                                          SendMessage(p->WndTrack, TBM_SETTHUMBLENGTH,TrackThumb,0);

                                   }

                            }

 

                            if (p->WndTitle)

                            {

                                   p->TitleTimeWidth = 0;

                                   p->TitleFontSize = TITLEFONT;

                                   p->TitleFont = WinFont(&p->Win,&p->TitleFontSize,0);

                                   p->TitleHeight = WinUnitToPixelY(&p->Win,TITLEHEIGHT);

                                   p->TitleBorder = WinUnitToPixelX(&p->Win,3);

                                   p->TitleWidth = r.right - r.left;

 

                                   if (Skin)

                                   {

                                          skinitem* i = &p->Skin[p->SkinNo].Item[SKIN_TITLE];

                                          p->TitleWidth = i->Rect.Width;

                                          p->TitleHeight = i->Rect.Height;

                                          MoveWindow(p->WndTitle,r.left + i->Rect.x,r.top + i->Rect.y,p->TitleWidth,p->TitleHeight,TRUE);

                                   }

                                   else

                                   {

                                          if (p->Win.ToolBarHeight)

                                          {

                                                 r.bottom -= p->TitleHeight;

                                                 MoveWindow(p->WndTitle,r.left,r.bottom,p->TitleWidth,p->TitleHeight,TRUE);

                                          }

                                          else

                                          {

                                                 MoveWindow(p->WndTitle,r.left,r.top,p->TitleWidth,p->TitleHeight,TRUE);

                                                 r.top += p->TitleHeight;

                                          }

                                   }

 

                                   p->TitleTop = (p->TitleHeight-WinUnitToPixelY(&p->Win,p->TitleFontSize))/2;

                            }

 

                            p->SkinArea.x = r.left;

                            p->SkinArea.y = r.top;

                            p->SkinArea.Width = r.right - r.left;

                            p->SkinArea.Height = r.bottom - r.top;/

 

                            if (!Skin)

                                   p->SkinViewport = p->SkinArea;

                            else

                            {

                                   p->SkinViewport = p->Skin[p->SkinNo].Item[SKIN_VIEWPORT].Rect;

                                   p->SkinViewport.x += p->SkinArea.x;

                                   p->SkinViewport.y += p->SkinArea.y;

                            }

 

                            if (p->Win.ToolBarHeight && !p->VolResizeNeeded)

                                   ResizeVolume(p);

                     }

 

                     p->Viewport = p->SkinViewport;

                     p->Viewport.x += p->Offset.x;

                     p->Viewport.y += p->Offset.y;

                     p->Player->Set(p->Player,PLAYER_SKIN_VIEWPORT,&p->Viewport,sizeof(rect));

                     p->Player->Set(p->Player,PLAYER_UPDATEVIDEO,NULL,0);

 

                     if (p->VolResizeNeeded)

                     {

                            ResizeVolume(p);

                            p->VolResizeNeeded = 0;

                     }

              }

       }

       else

       {

              GetClientRect(p->Win.Wnd,&r);

              p->Viewport.x = r.left + p->Offset.x;

              p->Viewport.y = r.top + p->Offset.y;

              p->Viewport.Width = r.right - r.left;

              p->Viewport.Height = r.bottom - r.top;

       }

 

       if (Rotated)

              p->Player->Set(p->Player,PLAYER_ROTATEEND,NULL,0);

 

       DEBUG_MSG4(DEBUG_VIDEO,T("Resize end %d,%d,%d,%d"),p->Viewport.x,p->Viewport.y,p->Viewport.Width,p->Viewport.Height);

}

 

int GetOrientation()

{

#if defined(TARGET_WINCE)

       if (Orientation < 0)

       {

              HKEY Key;

              context* p;

              char Buffer[256];

              DEVMODE* Mode = (DEVMODE*)Buffer;

 

              Mode->dmSize = 192;

              Mode->dmFields = DM_DISPLAYQUERYORIENTATION;

 

              if (QueryPlatform(PLATFORM_VER) >= 421 && // we don't trust this method on pre wm2003se systems

                     FuncChangeDisplaySettingsEx &&

                     FuncChangeDisplaySettingsEx(NULL, Mode, NULL, CDS_TEST, NULL) == DISP_CHANGE_SUCCESSFUL)

              {

                     Mode->dmFields = DM_DISPLAYORIENTATION;

                     FuncChangeDisplaySettingsEx(NULL, Mode, NULL, CDS_TEST, NULL);

 

                     switch ((&Mode->dmDisplayFrequency)[1]) //(Mode->dmDisplayOrientation)

                     {

                     case DMDO_0: Orientation = 0; break;

                     case DMDO_90: Orientation = DIR_SWAPXY | DIR_MIRRORUPDOWN; break;

                     case DMDO_270: Orientation = DIR_SWAPXY | DIR_MIRRORLEFTRIGHT; break;

                     case DMDO_180: Orientation = DIR_MIRRORUPDOWN | DIR_MIRRORLEFTRIGHT; break;

                     }

              }

 

              p = Context();

              if (Orientation < 0 && p->HwOrientation)

                     Orientation = p->HwOrientation(p->HwOrientationContext);

 

              if (Orientation < 0 && RegOpenKeyEx(HKEY_LOCAL_MACHINE, T("System//GDI//ROTATION"), 0, KEY_READ, &Key) == ERROR_SUCCESS)

              {

                     DWORD Value;

                     DWORD RegSize = sizeof(Value);

                     DWORD RegType;

 

                     if (RegQueryValueEx(Key, T("Angle"), 0, &RegType, (LPBYTE) &Value, &RegSize) == ERROR_SUCCESS)

                            switch (Value)

                            {

                            case 0: Orientation = 0; break;

                            case 90: Orientation = DIR_SWAPXY | DIR_MIRRORUPDOWN; break;

                            case 270: Orientation = DIR_SWAPXY | DIR_MIRRORLEFTRIGHT; break;

                            case 180: Orientation = DIR_MIRRORUPDOWN | DIR_MIRRORLEFTRIGHT; break;

                            }

 

                     RegCloseKey(Key);

              }

 

              if (Orientation < 0)

                     Orientation = 0;

       }

#else

       Orientation = 0;

#endif

       return Orientation;

}

五:界面模块接口交互分析

1.       控制模块通知界面模块

控制模块通知界面模块的回调函数为interface.c文件中的PlayerNotify函数。该函数将通过自定义Windows消息MSG_PLAYER将控制处理权交给主界面窗口。

PostMessage(p->Win.Wnd,MSG_PLAYER,PLAYER_PERCENT,Value);

 

case MSG_PLAYER:

       switch (wParam)

       {

       case PLAYER_EXIT_AT_END:

              if (p->CmdLineMode)

                     PostMessage(p->Win.Wnd,WM_COMMAND,IF_FILE_EXIT,0);

              break;

       case PLAYER_PERCENT:

              UpdatePosition(p);

              break;

       case PLAYER_LOADMODE:

              if (p->Wait != (bool_t)lParam)

              {

                     p->Wait = lParam;

                     if (p->Wait)

                     {

                            if (WaitBegin())

                                   UpdateClipping(p,1,0);

                     }

                     else

                            WaitEnd();

              }

              break;

       case PLAYER_FULLSCREEN:

              p->ForceFullScreen = lParam;

              if (GetForegroundWindow() == p->Win.Wnd || !lParam)

              {

                     ToggleFullScreen(p,lParam,1);

                     p->ForceFullScreen = 0;

              }

              break;

       case PLAYER_PLAY:

              RefreshButton(p,PLAYER_PLAY,&p->Play,IF_PLAY,0,1);

              RefreshButton(p,PLAYER_FFWD,&p->FFwd,IF_FASTFORWARD,4,1);

              UpdateSleepTimer(p);

              break;

       case PLAYER_BENCHMARK:

              if (p->Bench && p->Player->Get(p->Player,PLAYER_BENCHMARK,&t,sizeof(tick_t))==ERR_NONE)

              {

                     p->Bench = 0;

                     ToggleFullScreen(p,0,0);

                     WaitEnd();

                     if (p->WndTrack)

                            SetTrackThumb(p->WndTrack,1);

                     UpdateWindow(p->Win.Wnd);

                     WinPopupClass(BENCHRESULT_ID,&p->Win);

              }

              break;

       }

 

2.       界面模块发送指令给控制模块

界面模块主要通过使用interfacePlayer指针进行操作。具体操作主要参考interface.c中的Command函数。

static int Command(intface* p,int Cmd)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值