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开发环境中,播放本地视频的函数也可以播放网络视频,如果用早期的库,用一套代码就可以了;


好文章,来自【福优学苑@音视频+流媒体】
***【在线视频教程】***