VLC开发包编写简单播放器
好文章,来自【福优学苑@音视频+流媒体】
如果要写一个播放器,所有实现都是自己完成,这个就有点难度,而且非常费时,要了解媒体文件格式,视频解码,图像绘制,音视频同步等知识点,所以要完全实现还是比较麻烦的;
通常情况,可以用一些现成的库开发,如在windows上最常用的是DirectShow,但是DirectShow的学习有一点难度,而且关于解码器的东西还是需要安装如XviD,ffdshow等,建立链路时自己选择或智能选择解码器,而且也不是很容易,对于一般应用的开发来说还是比较有难度的;我之前用DirectShow编写了一个播放器,如果不是为了实时抓图,我会用VLC编写的;
--注释:当时因为对DirectShow很熟悉,所以用DirectShow编写播放器了,其实通过VLC的回调函数函数也可以直接获取视频图像,包括网络视频流图像,原理是一样的;
也可以在网上搜索开源的播放器,然后修改一些界面,不过一般的开源软件工程比较大;
这里我推荐一个比较简单的方法,用VLC SDK编写播放器,VLC是一个款平台开源的项目,还提供二进制安装包和开发包,这里我们用windows中的安装包直接安装,安装过程中选择安装sdk和ocx,这样就可以通过VC开发播放器了;
开发过程:
//简单播放示例
在VC中配置VLC安装目录中的include文件夹和lib文件夹:
示例如下:
这个例子是网上搜索的,简单修改一下:
libvlc_instance_t * vlc_ins = NULL; libvlc_media_player_t * vlc_player = NULL; libvlc_media_t * vlc_media = NULL; //播放文件 void CtestVLCDlg::OnBnClickedPlay() { // TODO: 在此添加控件通知处理程序代码 vlc_ins = libvlc_new(0, NULL); if(vlc_ins != NULL) { //创建一个示例: vlc_player = libvlc_media_player_new(vlc_ins); if(vlc_player != NULL) { // 通过文件路径创建一个媒体实例,这里是我的测试文件 vlc_media = libvlc_media_new_path(vlc_ins, "F:\\t.avi"); if(vlc_media != NULL) { // 解析媒体实例 libvlc_media_parse(vlc_media); // 获取媒体文件的播放长度, 返回 ms libvlc_time_t duration = libvlc_media_get_duration(vlc_media); // 此处是获取媒体包含多个的视频和音频轨以及其他类型的轨道信息 libvlc_media_track_info_t *media_tracks = NULL; int trackCount = libvlc_media_get_tracks_info(vlc_media, &media_tracks); // 这里是释放内存,但我测试的时候会有问题,还没仔细研究是为何 // free(media_tracks); // crash? // 把打开的媒体文件设置给播放器 libvlc_media_player_set_media(vlc_player, vlc_media); // 因为是windows系统,所以需要设置一个HWND给播放器作为窗口,这里就直接使用桌面窗口,这里仅是测试 libvlc_media_player_set_hwnd(vlc_player, /*::GetDesktopWindow()*/ AfxGetApp()->m_pMainWnd->m_hWnd ); // 开始播放视频 libvlc_media_player_play(vlc_player); } } } }
//播放完成后释放资源
void CtestVLCDlg::OnBnClickedstop() { libvlc_media_player_stop(vlc_player); libvlc_media_release(vlc_media); libvlc_media_player_release(vlc_player); libvlc_release(vlc_ins); }
通过这个简单示例可以了解VLC播放文件的过程,VLC在播放文件的时候会在内部创建播放线程,所以libvlc_media_player_play(vlc_player);播放视频后,程序不会阻塞;
可以开启定时器或线程监控播放进度,如果播放完成,就是否资源(我没有了解VLC播放完成后是否有回调函数或事件通知,如果有可以直接用);
VLC开发播放器,网上有很多资源,这里我推荐一个封装比较简明的资源 “基于VLC的MFC播放器 完整版”,可以再csdn都到这个资源;
VLC消息添加:
VLC有很多消息,可以通过添加回调函数通知:
示例代码:
if( m = libvlc_media_new_location (m_pVLC_Inst, szUTFName) ) { if ( ( m != NULL ) && ( m_pVLC_Player = libvlc_media_player_new_from_media(m) ) ) { libvlc_media_player_set_hwnd(m_pVLC_Player, m_hWnd); libvlc_media_player_play(m_pVLC_Player); // 事件管理 libvlc_event_manager_t *vlc_evt_man = libvlc_media_player_event_manager(m_pVLC_Player); libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerEndReached, ::OnVLC_EndReached, this); libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerPositionChanged, ::OnVLC_PositionChanged, this); ...... } }
但是如果按照上述代码,可能要添加好几十个函数才可以完成所有的消息判断,所以可以修改上述代码为,用循环添加所有消息到一个函数,然后在相应消息的函数中处理:
if( m = libvlc_media_new_location (m_pVLC_Inst, szUTFName) ) { if ( ( m != NULL ) && ( m_pVLC_Player = libvlc_media_player_new_from_media(m) ) ) { libvlc_media_player_set_hwnd(m_pVLC_Player, m_hWnd); libvlc_media_player_play(m_pVLC_Player); // 事件管理 libvlc_event_manager_t *vlc_evt_man = libvlc_media_player_event_manager(m_pVLC_Player); // libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerEndReached, ::OnVLC_EndReached, this); // libvlc_event_attach(vlc_evt_man, libvlc_MediaPlayerPositionChanged, ::OnVLC_PositionChanged, this); { int i = 0 ; for ( i = libvlc_MediaMetaChanged ; i< libvlc_VlmMediaInstanceStatusError; i++ ) { libvlc_event_attach(vlc_evt_man, i, OnVLC_LibVlc, this); } } } }
但是上述代码还是有一个确定,没有面向对象,一个消息回调函数是一个全局的函数,如果让一个类完成所有对象的各自相应,方法就是:
在全局的消息回调中,可以传入自定义参数,可以把当前对象的指针传入,就是 this 指针,然后在类中添加一个函数相应消息,在全局函数中通过this指针调用相关对象的消息函数,实例:
//封装相关的VLC函数;
class VLCclass { public: 。。。。。。 On_libvlc_event( event ); } void OnVLC_LibVlc(const libvlc_event_t *event, void *data) { if (data) { VLCclass * pPlayer = (VLCclass*)data; pPlayer->On_libvlc_event( event ); } }
Sample LibVLC Code
This sample code will (try to) play back an URL. There is also an example using SDL for video output.
#include <stdio.h> #include <stdlib.h> #include <vlc/vlc.h> int main(int argc, char* argv[]) { libvlc_instance_t * inst; libvlc_media_player_t *mp; libvlc_media_t *m; /* Load the VLC engine */ inst = libvlc_new (0, NULL); /* Create a new item */ m = libvlc_media_new_location (inst, "http://mycool.movie.com/test.mov"); //m = libvlc_media_new_path (inst, "/path/to/test.mov"); /* Create a media player playing environement */ mp = libvlc_media_player_new_from_media (m); /* No need to keep the media now */ libvlc_media_release (m); #if 0 /* This is a non working code that show how to hooks into a window, * if we have a window around */ libvlc_media_player_set_xwindow (mp, xid); /* or on windows */ libvlc_media_player_set_hwnd (mp, hwnd); /* or on mac os */ libvlc_media_player_set_nsobject (mp, view); #endif /* play the media_player */ libvlc_media_player_play (mp); sleep (10); /* Let it play a bit */ /* Stop playing */ libvlc_media_player_stop (mp); /* Free the media_player */ libvlc_media_player_release (mp); libvlc_release (inst); return 0; }
上面两个例子,有所不同,在较早期的VCL开发环境中,播放本地视频的函数也可以播放网络视频,如果用早期的库,用一套代码就可以了;
***【在线视频教程】***