基于libVLC的视频播放器

本文来自于:http://blog.csdn.net/leixiaohua1020/article/details/42363079

 

最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器

本文记录使用libVLC的开发的最简单的视频播放器示例。VLC Media Player是一款优秀的播放器,但是由于它的源代码编译的难度比较大,一直没有深入研究过它的开发方面的技术。此前触到了一些VLC开发方面的东西,因 此总结了一下libVLC的开发示例程序。

如何获取VLC的SDK

VLC开发所需的库文件可以有2种获取方法:

1.    自行编译
2.    直接从安装目录里面拷贝出来



第一种方法难度要大一些。尤其是在Windows下编译VLC是个比较麻烦的事情。一般情况下可以选择第二种方法获取VLC开发所需的文件。
开发VLC所需的文件的位置:

1.    动态链接库*.dll:安装目录下的libvlc.dll,libvlccore.dll以及plugins目录下的所有文件。
PS:VLC支持非常多的plugin。因此plugins目录的体积确实是非常大的。
2.    静态链接库*.lib:安装目录/sdk/lib
3.    头文件*.h:安装目录/sdk/include


新建一个VC工程后,把上述三类文件分别拷贝至新工程目录下,并且配置它们的路径之后,就可以使用libVLC进行开发了。

最简单的基于libVLC的视频播放器

使用libVLC开发一个播放器十分的容易。最简单的基于libVLC的视频播放器的流程图如下图所示。

流程图中包含了3个结构体:

libvlc_instance_t:代表一个libVLC的实例。
libvlc_media_t:代表一个可以播放的媒体。
libvlc_media_player_t:代表一个VLC媒体播放器(一个视频播放器播放一个视频)。注意VLC并不仅仅用于媒体播放。

创建或者以上3个结构体通过以下6个函数:

libvlc_new():创建libvlc_instance_t。
libvlc_media_new_path():创建libvlc_media_t。
libvlc_media_player_new_from_media():创建libvlc_media_player_t。
libvlc_media_player_release():释放libvlc_media_player_t
libvlc_media_release():释放libvlc_media_t。
libvlc_release():释放libvlc_instance_t。

可以已通过下面的函数控制媒体的播放或者暂停,这些函数都需要使用libvlc_media_player_t作为参数。这里处于简化的目的,只使用了播放和停止函数:

libvlc_media_player_play():播放。
libvlc_media_player_pause():暂停。
libvlc_media_player_stop():停止。

除了上述3个函数之外,还包括libvlc_media_player_set_position()等函数,这里不再一一记录。

几点注意事项

libvlc_media_t的创建

创 建libvlc_media_t有两种方法:libvlc_media_new_path()和 libvlc_media_new_location()。简单描述一下这两个函数的区别:libvlc_media_new_location()用于 打开协议,而libvlc_media_new_path()用于打开文件。因而传递给libvlc_media_new_path()的就是普通的文件 路径(绝对路径例如D:\xxx.flv,或者相对路径例如xxx.flv),而传递给libvlc_media_new_location()的就是协 议地址(例如"udp://….","http://")。但是这里有一点需要注意,在VLC中"文件"也属于一种广义上的"协议"。因此使用 libvlc_media_new_location()也可以打开文件,但是必须在文件路径前面加上"文件协议"的标记"file:///"。例如打开 "F:\movie\cuc_ieschool.flv"下的视频,实际使用的代码如下所示。

libvlc_media_new_location (inst, "file:///F:\\movie\\cuc_ieschool.flv");

此外,VLC还支持很多"神奇"的协议,比如输入"screen://"协议就可以进行屏幕录制,代码如下。

libvlc_media_new_location (inst, "screen://");

把libVLC的弹出窗口嵌入到程序中

在这里我只实践过Windows下把libVLC的弹出窗口嵌入到程序中。将窗口或者控件的句柄传递给libvlc_media_player_set_hwnd()函数即可。
这里有一点需要注意,如果把libVLC弹出窗口嵌入到程序中的话,"全屏"功能就不能使用了。

关于libVLC加载的问题

在 libVLC中可以通过 libvlc_media_player_get_length(),libvlc_video_get_width(),libvlc_video_get_height() 等函数获取到视频的时长,宽,高等信息。但是有一个很奇怪的现象:如果在调用完libvlc_media_player_play()之后立即调用上述3 个函数的话,返回的值都是0,只有"等待"一段时间(例如调用sleep())后再调用上述函数,才能得到正确的数值。对于这种现象,我觉得可能是 libVLC加载完成之后,才能通过上述几个函数获得正确的值(自己推测的,还没有深究)。

 #include <Windows.h>   
 #include "vlc/vlc.h"int main(int argc, char* argv[])   
  {   
      libvlc_instance_t * inst;   
      libvlc_media_player_t *mp;   
      libvlc_media_t *m;   
         
      libvlc_time_t length;   
      int width;   
      int height;   
      int wait_time=5000;   
    
      //libvlc_time_t length;   
    
      /* Load the VLC engine */   
      inst = libvlc_new (0, NULL);   
      
      //Create a new item   //Method 1:   //m = libvlc_media_new_location (inst, "file:///F:\\movie\\cuc_ieschool.flv");   //Screen Capture   //m = libvlc_media_new_location (inst, "screen://");   //Method 2:   
      m = libvlc_media_new_path (inst, "cuc_ieschool.flv");   
            
      /* 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);   
     
      // play the media_player   
      libvlc_media_player_play (mp);   
    
      //wait until the tracks are created   
      _sleep (wait_time);   
      length = libvlc_media_player_get_length(mp);   
      width = libvlc_video_get_width(mp);   
      height = libvlc_video_get_height(mp);   
      printf("Stream Duration: %ds\n",length/1000);   
      printf("Resolution: %d x %d\n",width,height);   
      //Let it play    
      _sleep (length-wait_time);    
        
      // Stop playing   
      libvlc_media_player_stop (mp);   
     
      // Free the media_player   
      libvlc_media_player_release (mp);   
     
      libvlc_release (inst);   
     
      return 0;   
  }

最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器(图形界面版)

本文记录使用libVLC开发的一个简单的图形界面的视频播放器。由于是示例程序,只包含了最简单的媒体播放方面的功能。其中有一些功能还不完善,有时间以后再做修改。

 

 

最简单的基于libVLC的视频播放器(图形界面版)

这 是使用libVLC基于MFC开发的一个示例播放器。实现了一个播放器的基本功能:播放,暂停/继续,停止,播放时间轴的显示,以及从任一点开始播放媒 体。并且支持将媒体文件拖拽至播放器进行播放。播放前将媒体文件的路径输入到"URL"栏中,然后单击"Start"即可开始播放。

播放时候的效果截图如下所示。

源代码比较长,不再详细记录。简单记录一下其中几个主要功能的实现机制。

视频的播放/暂停/继续/停止

播放

视频"播放"的源代码如下所示。简单来说,完成了以下视频播放的初始化工作:
(1)    输入的URL转换为UTF-8编码(后文详细记录)
(2)    将显示视频画面的控件的句柄提供给libVLC
(3)    初始化libVLC并开始播放
(4)    开启定时器,用于更新视频播放的进度(后文详细记录)

 

void CplayerGUIDlg::OnBnClickedStart()   
{   
    CStringW cstr_url;   
   
#ifdef _UNICODE   
    m_url.GetWindowText(cstr_url);   
#else   
    USES_CONVERSION;   
    CStringA cstr_urla;   
    m_url.GetWindowText(cstr_urla);   
    cstr_url.Format(L"%s",A2W(cstr_urla));   
#endif   
   
    std::string str_url;   
    UNICODE_to_UTF8(cstr_url, str_url);   
    const char *char_url=str_url.c_str();   
   
    if(strcmp(char_url,"")==0){   
        AfxMessageBox(_T("Input URL is NULL!"));   
        return;   
    }   
       
    HWND screen_hwnd=NULL;   
    screen_hwnd = this->GetDlgItem(IDC_SCREEN)->m_hWnd;    
   
    if(playerstate!=STATE_PREPARE){   
        AfxMessageBox(_T("Media is playing now."));   
        return;   
    }   
   
   
     /* Create a new item */   
     //m = libvlc_media_new_location (libvlc_inst, "http://mycool.movie.com/test.mov");   
   
     libvlc_m = libvlc_media_new_path (libvlc_inst, char_url);   
   
     /* Create a media player playing environement */   
     libvlc_mp = libvlc_media_player_new_from_media (libvlc_m);   
        
     /* No need to keep the media now */   
     libvlc_media_release (libvlc_m);   
    
    //on windows   
     libvlc_media_player_set_hwnd (libvlc_mp,screen_hwnd);   
    
     /* play the media_player */   
     int x=libvlc_media_player_play (libvlc_mp);   
       
     //_sleep (30000); /* Let it play a bit */   
       
   
    playerstate=STATE_PLAY;   
    SetBtn(STATE_PLAY);   
    SetTimer(1,1000,NULL);   
}

暂停/继续

视频"暂停/继续"的源代码如下所示。其中调用了libvlc_media_player_set_pause()设定"暂停"或者是"继续"。

void CplayerGUIDlg::OnBnClickedPause()   
{   
    if(playerstate==STATE_PLAY){   
        libvlc_media_player_set_pause(libvlc_mp,1);   
        playerstate=STATE_PAUSE;   
        GetDlgItem(ID_PAUSE)->SetWindowText(_T("Resume"));   
    }else if(playerstate==STATE_PAUSE){   
        libvlc_media_player_set_pause(libvlc_mp,0);   
        playerstate=STATE_PLAY;   
        GetDlgItem(ID_PAUSE)->SetWindowText(_T("Pause"));   
    }   
}

停止

视频"停止"的源代码如下所示。其中调用了libvlc_media_player_stop()停止视频播放,并且调用libvlc_media_player_release()释放相应的libvlc_media_player_t结构体。

void CplayerGUIDlg::OnBnClickedStop()   
{   
    if(libvlc_mp!=NULL){   
        libvlc_media_player_stop (libvlc_mp);   
        libvlc_media_player_release (libvlc_mp);   
        KillTimer(1);   
    }   
       
    SystemClear();   
}

视频播放进度杂时间轴的显示

随着视频的播放,需要在视频播放进度的时间轴上更新播放进度信息。在程序中使用了一个定时器完成这个功能。
在视频开始播放的时候,调用SetTimer()开启定时器。时间间隔设置为1000ms。

SetTimer(1,1000,NULL);

在视频停止播放的时候,调用KillTimer()结束定时器。

KillTimer(1);

在定时器的消息响应函数中,调用libvlc_media_player_get_time()获取当前视频的播放进度,此外调用libvlc_media_player_get_length()获取视频的总时长。
经过计算之后,就可以把计算的结果设置到相应的编辑框(Edit Control)以及滑动控制条(Slider Control)上。

 

void CplayerGUIDlg::OnTimer(UINT_PTR nIDEvent)   
{   
    if (nIDEvent == 1){   
        CString curtimestr,durationstr;   
        int curtime;   
        int duration;   
        int tns, thh, tmm, tss;   
        int progress;   
        //ms   
        curtime = libvlc_media_player_get_time(libvlc_mp);   
        if(curtime!=0){   
            //change to second   
            tns = curtime/1000;   
            thh  = tns / 3600;   
            tmm  = (tns % 3600) / 60;   
            tss  = (tns % 60);   
            curtimestr.Format(_T("%02d:%02d:%02d"),thh,tmm,tss);   
            m_curtime.SetWindowText(curtimestr);   
        }   
        duration  = libvlc_media_player_get_length(libvlc_mp);   
        if(duration!=0){   
            tns = duration/1000;   
            thh  = tns / 3600;   
            tmm  = (tns % 3600) / 60;   
            tss  = (tns % 60);   
            durationstr.Format(_T("%02d:%02d:%02d"),thh,tmm,tss);   
            m_duration.SetWindowText(durationstr);   
   
            progress=curtime*100/duration;   
            m_progress.SetPos(progress);   
        }   
    }   
   
    //Stop in the end   
    if(libvlc_media_player_get_state(libvlc_mp)==libvlc_Ended)   
        OnBnClickedStop();   
   
   
    CDialogEx::OnTimer(nIDEvent);   
}

视频播放点的调整

当鼠标拖动滑动控制条(Slider Control)控件上的滑块的时候,需要根据拖动的位置设置视频的播放进度。此时调用libvlc_media_player_set_position()设定视频的播放进度。消息响应函数中的代码如下所示。

void CplayerGUIDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)   
{   
    if (pScrollBar->GetSafeHwnd() == m_progress.GetSafeHwnd()){   
        float posf=0.0;   
        if(nSBCode==SB_THUMBPOSITION){   
            posf=(float)nPos/100.0;   
            libvlc_media_player_set_position(libvlc_mp,posf);   
        }   
    }   
    CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);   
}

libVLC中输入中文文件路径问题

libVLC 使用英文作为输入路径的时候是没有问题的。但是当我们直接传递中文路径的时候,会出现libVLC将中文解析为乱码从而导致无法播放的问题。这个问题卡了 我一阵子时间。造成这一问题的原因在于VLC的输入文件路径是使用UTF-8编码的。因此我们需要将输入路径转码为UTF-8编码。转码之后这一问题即得 到了解决。

Unicode转码为UTF-8的函数代码如下所示。

void CplayerGUIDlg::UNICODE_to_UTF8(CStringW& unicodeString, std::string& str)   
{   
    int stringLength = ::WideCharToMultiByte(CP_UTF8, NULL, unicodeString, wcslen(unicodeString), NULL, 0, NULL, NULL);   
   
    char* buffer = new char[stringLength + 1];   
    ::WideCharToMultiByte(CP_UTF8, NULL, unicodeString, wcslen(unicodeString), buffer, stringLength, NULL, NULL);   
    buffer[stringLength] = '\0';   
   
    str = buffer;   
   
    delete[] buffer;   
}

最简单的基于libVLC的例子:最简单的基于libVLC的推流器

 

本文记录基于libVLC的最简单的推流器。该推流器可以将本地的视频文件转码后推送至目标流媒体服务器(也可以是一个组播地址)。

最简单的基于libVLC的推流器

 

该推流器的代码十分简单,只用到了几个函数:

libvlc_new():创建libvlc_instance_t。
libvlc_vlm_add_broadcast():增加一个广播(broadcast)。
libvlc_vlm_play_media():播放指定名称的广播(broadcast)。
libvlc_vlm_stop_media():停止指定名称的广播(broadcast)。
libvlc_vlm_release():释放ibvlc_instance_t。


本示例的输入视频文件为"cuc_ieschool.flv"。这个推流器实现了:

  • 输入视频转码为H.264
  • 音频转码为mp2
  • 封装格式设置为MPEG-TS
  • 以UDP的形式发送至组播地址"udp://233.233.233.233:6666"

在程序发送广播的同时,会弹出一个窗口显示当前正在发送的视频。

 

#include <Windows.h>   
#include "vlc/vlc.h"   
   
   
int main(int argc, char **argv) {   
    libvlc_instance_t *vlc;   
    const char *url;   
    //Send File   
    //Transcode it. Video codec use x264. Audio codec use mpga.   
    //Mux it to mpegts format.   
    //And stream it to udp://233.233.233.233:6666   
    /*  
    const char *sout = "#transcode{vcodec=h264,fps=25,venc=x264{preset=ultrafast,"\  
        "profile=main,tune=zerolatency},vb=512,scale=0.5,"                        \  
        "acodec=mpa,aenc=ffmpeg,ab=64,channels=2}"                                \  
        ":standard{access=udp,mux=ts,dst=233.233.233.233:6666}";  
    */   
    //Send and playing at same time   
    const char *sout = "#transcode{vcodec=h264,fps=25,venc=x264{preset=ultrafast,"\   
        "profile=baseline,tune=zerolatency},vb=512,"                              \   
        "acodec=mpga,ab=64,channels=2}"                                           \   
        ":duplicate{dst=display,dst=standard{access=udp,mux=ts,dst=233.233.233.233:6666}}";   
    const char *media_name = "Lei's test";   
   
    //Screen Capture   
    //url = "screen://";   
   
    url = "cuc_ieschool.flv";   
       
    vlc = libvlc_new(0, NULL);   
    libvlc_vlm_add_broadcast(vlc, media_name, url, sout, 0, NULL, true, false);   
    libvlc_vlm_play_media(vlc, media_name);   
       
    //play 30s   
    _sleep(30000);    
   
    libvlc_vlm_stop_media(vlc, media_name);   
    libvlc_vlm_release(vlc);   
    return 0;   
}
posted @ 2015-05-17 17:33  Mr.Rico  阅读(...)  评论(... 编辑 收藏