背景
最近在学习duilib这个库,看了网上Alberl的教程,他那个仿迅雷播放器做的不错,我就直接拿来学习duilib了。不过这个播放器有个缺点,就是无法双击全屏,也就是鼠标放到libVLC播放窗口时无法响应消息,消息都被libVLC内部处理了。这对我们而言不是很方便。因为有时我们需要双击全屏,或者弹出鼠标右键菜单做一些操作。后来上网查了下,好多人遇到这个问题。下面是一些查到的解决方法。
解决libVLC无法响应鼠标消息
如下是查到的一些方法:
1)使用全局钩子;
2)修改libVLC鼠标消息处理代码,重新编译;
3)禁用子窗口消息。
第一种方法不安全,容易被杀毒软件干掉,而且效率不高,第二种方法麻烦,编译就得花你好多时间,而且很麻烦,第三种方法比较简单,解决方法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// First step is start a timer when you play a video, // Second step : in the timer function i call : EnumChildWindows(MyWindow_HWND, EnumerateVLC, NULL); // Third step : if EnumerateVlc get some child window these window is the VlcEventWindow, and need disable it, to reach mouse events on MyWindow BOOL CALLBACK EnumerateVLC(HWND hWndvlc, LPARAM lParam) { EnableWindow(hWndvlc, FALSE); // And kill timer, i only need get this handle one time. return TRUE; } // When EnumerateVLC is called all mouse events are redirected to MyWindow |
具体实现见下面。
基于duilib实现
duilib学起来还是很容易上手的,这里我的代码是基于Alberl的仿迅雷播放器。最后实现的界面如下:
按照上面的解决方法,在这个程序中我是这么解决无法响应消息的:
1)当开始播放某个文件后,创建一个一秒的定时器(也可以不创建,直接跳到直接第二步,创建定时器是为了确保我们处理时VLC窗口已经生成);
1 |
SetTimer(NULL, 1, 1000, TimeProc); |
2)在定时器的回调函数中枚举得到VLC创建的窗口的句柄,通过spy++可以了解到libVLC创建的播放窗口名为:VLC video output,获取到VLC窗口的句柄后使用EnableWindow
函数禁用掉键鼠输入,EnableWindow
函数的作用是允许/禁止指定的窗口或控件接受鼠标和键盘的输入,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//定时器回调 void CALLBACK TimeProc( HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) { //我的播放器窗口名称为JCHPlayer,也可以直接获取主程序窗口句柄 WCHAR *strWindwoName = L"JCHPlayer"; HWND hNMMainWnd = FindWindowEx(NULL, NULL, NULL, strWindwoName); if (hNMMainWnd != NULL) { EnumChildWindows(hNMMainWnd, EnumerateVLC, NULL); } } //枚举得到VLC播放窗口句柄 BOOL CALLBACK EnumerateVLC(HWND hWndvlc, LPARAM lParam) { TCHAR szWndTitle[1024]; int nLen = GetWindowText(hWndvlc, szWndTitle, 1024); if (0!= nLen) { //禁用鼠标消息 EnableWindow(hWndvlc, FALSE); KillTimer(NULL, 1); } return TRUE; } |
通过如上方法,在VLC播放窗口上的鼠标键盘消息我们都可以获得,这样就可以去实现自己想要的功能。比如我在全屏时响应WM_MOUSEMOVE
消息,实现底部播放面板自动隐藏。双击全屏也很简单,当响应双击消息时,只显示作为libvlc父窗口那个控件,其他控件都隐藏即可。整个播放器的代码我已经上传到Github。
地址:https://github.com/yjfxfjch/JCHPlayer
我是用的是VS2015编译,低版本VS可能无法直接打开编译。下面一节是使用MFC做界面实现的版本。
基于MFC实现
1)在MFC对话框程序中,首先添加一个控件,这里我添加了一个Picture Contron:IDC_PLAYWND;
2)获得IDC_PLAYWND控件句柄;
1 |
gPlayHwnd = GetDlgItem(IDC_PLAYWND)->GetSafeHwnd(); |
3)让libVLC播放对象设置gPlayHwnd 为播放窗口句柄,这样libVLC播放窗口就成为IDC_PLAYWND控件的子窗口;
1 |
libvlc_media_player_set_hwnd (mp, gPlayHwnd ); |
4)开始播放后创建一个定时器(也可以不创建,直接EnableWindow
相应窗口句柄);
1 |
::SetTimer(NULL, 1, 1000, TimeProc); |
5)定时器回调函数以及处理过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//定时器回调 void CALLBACK TimeProc( HWND hwnd, UINT message, UINT idTimer, DWORD dwTime) { EnumChildWindows(gPlayHwnd, EnumerateVLC, NULL); } BOOL CALLBACK EnumerateVLC(HWND hWndvlc, LPARAM lParam) { TCHAR szWndTitle[1024]; int nLen = GetWindowText(hWndvlc, szWndTitle, 1024); if (0 != nLen) { //禁用鼠标消息 EnableWindow(hWndvlc, FALSE); KillTimer(NULL, 1); } return TRUE; } |
在上述代码中,我们通过之前得到的IDC_PLAYWND
控件句柄枚举得到子窗口VLC播放窗口句柄,接着通过EnableWindow
函数禁止VLC播放窗口接受鼠标键盘输入。这时我们的程序就可以响应鼠标点击libVLC播放窗口的消息了;
6)设置全屏,主要是设置IDC_PLAYWND
控件全屏时占满整个屏幕,然后隐藏其他控件以及标题栏,这样VLC子窗口就可以全屏播放了。不需要使用libvlc_set_fullscreen
这个内置api,使用这个api无法达到效果。
最后实现的简单版本如下:
MFC版本支持双击全屏的libvlc播放器代码我也上传到Github,具体的可以去看下。
Github地址:https://github.com/yjfxfjch/SimpleVlcPlayer
文章评论
博主好厉害啊。。我最近也在研究VLC,可以加个好友吗,我的QQ770552117
@zhao 有什么问题可以发邮件问我,我现在很少用QQ的。
博主你好。我这使用vlc的webplugin做网页版的播放器,其中就需要js去获取鼠标点击事件。请问博主这个方法是否可以使用于html上。或者博主是否知道什么更好的方法。谢谢指教
@liwei 我这个是通过系统api实现的,js肯定没那么大权限,只能通过修改你vlc插件源代码了。现在web都不提倡用这种NPAPI插件或activex控件了,浏览器也都默认禁用。最好的方法是用js写一个,现在html5功能也够强大。你可以参考下flv.js,修改下,基本上各种协议都能实现播放。
hi,哥们,我从 https://github.com/yjfxfjch/JCHPlayer 这里下载,
然后更新了下Duilib(https://github.com/qdtroy/DuiLib_Ultimate)库,
发现播放时播放区域总是黑色,但是有进度在前进,请问下,这个可能是因为什么导致的?
@Jerry
我有空看下,好久的代码了,到时给你回复
调试发现,class CWndUI: public CControlUI 中的setpos不会被调用,然后对比了您的duilib库,发现改动有点大,感觉应该是在消息回调这边可能您有做了些特殊处理,但是代码量有点,所以只能麻烦博主了
@Jerry
现在太忙了,没时间看这些了,靠你自己了,我已经不搞界面这一套了,当时我的界面库都是官方下的,没改动过
博主你好。请问怎么调用音频的频谱?那个接口一直找不到
@sean
抱歉,我找了下也没找到,这个要自己写代码计算了,反正就那几个数学变换
CDuiFrameDlg *pFrame = new CDuiFrameDlg(_T("Player.xml")); Player.xml哪里可以下载到?
谢谢楼主。
@菲儿
https://github.com/yjfxfjch/JCHPlayer/tree/master/Release/skin
其实,最简单的就是把libvlc_media_player_set_hwnd的那个窗口设成禁用就可以了
求助...............使用网易nim_duilib时,创建的子窗口无法显示视频,报错core vout display error: Failed to set on top
@jy sorry,已经不搞windows客户端开发了