MFC+DuiVision结合VLC播放器开发直播客户端

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012431412/article/details/53152321

MFC+DuiVision结合VLC播放器开发直播客户端

说明:windows 10 VS2015社区版

关键字:c++ VisualStudio DuiVision VLC播放器

开发这个视频播放器的需求很简单:实现远程直播视频查看。实时点播、直播,VLC可以搭建一个直播客户端,然后再基于VLC开发视频播放器客户端查看直播视频。本文只涉及到客户端看直播的功能所涉及到的开发方法,没有过深的讲解直播等技术。

Duivision

参照官网说明,duivision是基于DirectUI技术开发,DirectUI一般是指将所有的界面控件都绘制在一个窗口上,这些控件的逻辑和绘图方式都必须自己进行编写和封装,而不是使用Windows控件,所以这些控件都是无句柄的。
DirectUI技术需要解决的主要问题如下:

  • 窗口的子类化,截获窗口的消息
  • 封装自己的控件,并将自己的控件绘制到该窗口上
  • 封装窗口的消息,并分发到自己的控件上,让自己的控件根据消息进行相应和绘制
  • 根据不同的行为发送自定义消息给窗口,以便程序进行调用
  • 一般窗口上控件的组织使用XML来描述

通常DirectUI的界面库都采用XML配置文件+图片+控制脚本(Lua、Javascript等)的开发方式,非常类似于Web程序的开发方式,当然这里面控制脚本也可以直接使用C++代码来实现。这种开发方式可以大大提高开发效率,将程序员从繁琐的界面工作中解脱出来,并且通过美工的设计,可以使界面更美观
DuiVision开源下载地址
源码目录结构
DuiVision目录结构
其中使用源码中的DuiVision文件夹中的内容,其中包含08、10、13、15版本的工程,使用的时候根据自己的VS选择工程引入。

打开VS创建自己的MFC工程,选择MFC应用程序,选择“基于对话框”和使用Unicode库,其他默认,创建之后将IDE生成的按钮和控件删除,只保留一个什么都没有的干净的对话框。其中部分如图:

这里写图片描述
这里写图片描述

然后一路“下一步”或者直接finish创建空白的MFC工程,创建结果如图(将默认生成的控件删除):

这里写图片描述

然后引入DuiVision,即前文说到的源代码中的DuiVision文件夹。先将DuiVision拷贝到工程目录中:

工程目录结果

然后,在VS中:右键Solution->add->existingProject找到DuiVison工程
选择合适的版本
当前VS是15版,所以选择DuiVision.2015.vcxproj
根据以下图配置项目的资源:

这里写图片描述

这里写图片描述

AdditionLibrary Directories 是DuiVision文件夹中Lib文件夹,我将其复制到项目根目录下所以值是../Lib;

(下图含有vlc字样的lib是后面将说到的vlc播放器要用到的)
链接动态库
然后将程序exe生成位置改为项目根目录下的bin目录,这是DuiVision程序的一个要求(控件等xml位置位于项目的EXE目录下)。
这里写图片描述

到此,使用DuiVision开发界面的环境搭建完毕,接下来进行界面开发。
界面使用XML开发,如觉得开发麻烦可以直接将源代码案例中的xml、skins以及plugins文件夹拷贝到工程的bin目录下

这里写图片描述

在xml文件夹中的resource.xml文件类似程序的主界面的入口,在其中定义界面的按钮、背景、文字以及加载的控件等资源,以及程序中使用到的全局变量。
官方说明官方开发文档传送门

A 编写界面

基于 DuiVision 界面库的程序,需要有一个默认的资源定义 XML 文件,此文件默认的位置是exe 文件所在路径下的 xml\resource.xml 文件,如果使用了 zip 压缩文件来保存所有资源文件,则此文件的位置是在压缩包中的 xml\resource.xml 文件。此文件中可以定义程序的全局配置、XML 文件、字体、图片、文字等资源。

<!—这是手册中定义的图片资源-->
<res type="img" name="IDB_MAIN_FRAME" file="skins\WindowsBack.png" />
<res type="img" name="IDB_BT_CLOSE" file="skins\BT_CLOSE.png" />
<res type="img" name="IDB_BT_MIN" file="skins\BT_MIN.png" />
<res type="img" name="IDB_BT_MENU" file="skins\BT_MENU.png" />
<res type="img" name="IDB_BT_SKIN" file="skins\BT_SKIN.png" />
<res type="img" name="IDB_TAB_1" file="skins\Tab1.png" />
<res type="img" name="IDB_TAB_2" file="skins\Tab2.png" />
<res type="img" name="IDB_ICON_INFO" file="skins\info.png" />
<res type="img" name="IDB_ICON_WARN" file="skins\warning.png" />
<res type="img" name="IDB_ICON_ERROR" file="skins\error.png" />
<res type="img" name="IDB_MENU_UPDATE" file="skins\MENU_UPDATE.png" />

其中name属性的值可以在其他xml文件和c++代码中使用。
界面中要使用的元素、控件均在resource.xml文件中引用,比如界面的主窗口均定义在type=”xml”的元素中:

xml界面

B 编写c++代码

界面编写完了之后就是在VS工程中引用和使用界面的时候了。
在主程序的 App 类 InitInstance()函数中添加 DuiVision 库的引用代码,示例代码如下:

// 初始化DuiVision界面库,可以指定语言,dwLangID为表示自动判断当前语言
// 1116是Demo程序的应用程序ID,每个DUI应用程序应该使用不同的ID
// ID主要用于进程间通信传递命令行时候区分应用
// IDD_DUIVISIONDEMO_DIALOG是工程中创建的那个对话框资源ID,所有窗口都是共用此ID的
// 第三个参数可以指定资源文件名,如果不指定默认使用xml\resource.xml的定义进行资源的加载,资源文件名的定义方式参考下面的说明
DWORD dwLangID = 0;
new DuiSystem(m_hInstance, dwLangID, _T("DuiVisionDemo.ui"), 1116,
IDD_DUIVISIONDEMO_DIALOG, "");
// 创建主窗口,dlg_main即在上文resource.xml文件中,res元素中type=”xml”,name=”dlg_main”中的dlg_main
CDlgBase* pMainDlg = DuiSystem::CreateDuiDialog(_T("dlg_main"), NULL, _T(""), TRUE);
// 给主窗口注册事件处理对象
CDuiHandlerMain* pHandler = new CDuiHandlerMain();
pHandler->SetDialog(pMainDlg);
DuiSystem::RegisterHandler(pMainDlg, pHandler);
// 初始化提示信息窗口
DuiSystem::Instance()->CreateNotifyMsgBox(_T("dlg_notifymsg"));
// 按照非模式对话框创建主窗口,可以设置为默认隐藏
pMainDlg->Create(pMainDlg->GetIDTemplate(), NULL);
//pMainDlg->ShowWindow(SW_HIDE);
INT_PTR nResponse = pMainDlg->RunModalLoop();
// 如果是按照模式对话框运行主窗口,只要改为如下代码就可以
//INT_PTR nResponse = pMainDlg->DoModal();
// 释放DuiVision界面库的资源 
DuiSystem::Release();

界面创建之后,现在为界面添加响应事件。除了界面的描述之外,最主要的工作就是业务逻辑的处理,为了将业务逻辑和界面展示能够更好的分离,DuiVision 中定义了事件处理基类,所有的业务逻辑都应该写在派生的事件处理类中,并把事件处理对象注册到相应的对话框或控件上,这样对应的子控件有事件需要处理的时候,就会自动调用注册的事件处理对象的相应函数。事件处理类只要在处理函数中根据控件的 ID 或名字决定该做什么事情,写相应的处理代码就可以。事件处理类中同时提供了一些函数方便根据 ID 或名字获取到对应的控件对象,并对控件进行操作,例如改变控件文字、获取控件的某个状态等。事件处理基类是 CDuiHandler,这个类的定义如下,提供了获取控件对象、设置控件的一些参数的函数,方便在事件处理类中对控件的操作:

class CDuiHandler{
    public:
        CDuiHandler(void);
        virtual ~CDuiHandler(void);
        LRESULT OnDuiMsgNotifyButton1 (UINT uID, CString strName, UINT Msg, WPARAM wParam, LPARAM lParam);
    protected:
        CDuiObject* m_pDuiObject; // 关联的DUI对象

    //消息处理定义,notify_button_1为xml文件中button的name值,BUTTOM_UP为DuiVision定义的事件名称,OnDuiMsgNotifyButton1这为自己编写的BUTTOM_UP事件的响应代码。
    DUI_DECLARE_MESSAGE_BEGIN(CDuiHandlerMain)
    DUI_CONTROL_NAMEMSG_MESSAGE(L"notify_button_1",BUTTOM_UP, OnDuiMsgNotifyButton1)
    DUI_DECLARE_MESSAGE_END()
};

对以上代码在cpp文件中的实现:

先include包含以上代码的.h文件,然后写如下代码:
LRESULT CDuiHandlerMain::OnDuiMsgMsgBoxButton1(UINT uID, CString strName, UINT Msg, WPARAM
wParam, LPARAM lParam)
{
DuiSystem::DuiMessageBox(NULL, _T("演示对话框!"));
return TRUE;
}

此程序的功能是鼠标点击一个名叫“notify_button_1”的按钮,当鼠标离开按钮时,弹出一个对话框。

VLC创建播放器窗口

将vlc视频播放器结合到MFC DuiVision 程序中
VLC官网下载播放器并安装,安装后使用安装目录下的libvlc.dlllibvlccore.dll,将两个库拷贝放到工程的Lib目录下,并修改工程的属性配置中添加引用到这两个库,参考前文引用DuiVision.2015d.lib (项目属性->linker->input->additional Dependencies的步骤)。此外还需要include vlc的一些开发代码,在当前(2016年11月11日)我下载的播放器中没有找到,所以我打包作为附加资源放在文后。
使用播放器就很简单了,直接上测试代码:

    LRESULT doCennectionHandler(UINT uID, CString strName, UINT Msg, WPARAM wParam, LPARAM lParam);
    LRESULT disCennectionHandler(UINT uID, CString strName, UINT Msg, WPARAM wParam, LPARAM lParam);
    LRESULT doPrintScreenHandler(UINT uID, CString strName, UINT Msg, WPARAM wParam, LPARAM lParam);

public:
    CPoint          m_ptControlImageNormal;
    CDuiFlashCtrl*  m_flash;
    CStatic *       m_pFlashPlayer;
    UINT_PTR        m_playerTimer;
    libvlc_instance_t * inst;
    libvlc_media_player_t * player;
    libvlc_media_t * media;
    libvlc_time_t   m_TotalTime;


    DUI_DECLARE_MESSAGE_BEGIN(CDuiMainHandler)
        DUI_CONTROL_NAMEMSG_MESSAGE(L"button.connect", MSG_BUTTON_UP, doCennectionHandler)
    DUI_DECLARE_MESSAGE_END()

LRESULT CDuiMainHandler::doCennectionHandler(UINT uID, CString strName, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (player != NULL) {
        libvlc_media_player_release(player);
    }
    inst = libvlc_new(0, NULL);
    media = libvlc_media_new_location(inst, "rtp://192.168.31.109:5004");
    player = libvlc_media_player_new_from_media(media);
    libvlc_media_release(media);

    HWND hw = m_pFlashPlayer->GetSafeHwnd();
    libvlc_media_player_set_hwnd(player, hw);//此处应先使用CStatic动态创建一个控件,获取句柄,因为官网说到duivsion创建的控件是没有句柄的,所以,这里为了将VLC播放器指定到duivision窗口中,CStatic * m_pFlashPlayer->Create(_T(""), WS_CHILD | WS_VISIBLE , CRect(50, 55, 790, 535), m_pDlg, 12345);
    libvlc_media_player_play(player);
    m_TotalTime = libvlc_media_player_get_length(player);
    return true;
}

当点击button.connect按钮之后,就能播放192.168.31.109:5004的视频了。
额,对于这个播放地址,使用VLC播放器发送的直播流,可以自己使用vlc播放器搭建一个本地的视屏直播源就行。对于其它操作,可以之间查看vlc源代码。Done!


附加资源:VLC开发库

展开阅读全文

没有更多推荐了,返回首页