本文来自于:http://blog.csdn.net/leixiaohua1020/article/details/42363079
?
最简单的基于libVLC的例子:最简单的基于libVLC的视频播放器
本文记录使用libVLC的开发的最简单的视频播放器示例。VLC Media Player是一款优秀的播放器,但是由于它的源代码编译的难度比较大,一直没有深入研究过它的开发方面的技术。此前触到了一些VLC开发方面的东西,因 此总结了一下libVLC的开发示例程序。
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的视频播放器的流程图如下图所示。
流程图中包含了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_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"下的视频,实际使用的代码如下所示。
[cpp]
view plaincopy
- libvlc_media_new_location?(inst,?"file:///F:\\movie\\cuc_ieschool.flv");??
此外,VLC还支持很多"神奇"的协议,比如输入"screen://"协议就可以进行屏幕录制,代码如下。
[cpp]
view plaincopy
- libvlc_media_new_location?(inst,?"screen://");??
?
在这里我只实践过Windows下把libVLC的弹出窗口嵌入到程序中。将窗口或者控件的句柄传递给libvlc_media_player_set_hwnd()函数即可。
这里有一点需要注意,如果把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)????开启定时器,用于更新视频播放的进度(后文详细记录)
[cpp]
view plaincopy
- 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()设定"暂停"或者是"继续"。
[cpp]
view plaincopy
- 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结构体。
[cpp]
view plaincopy
- void?CplayerGUIDlg::OnBnClickedStop()??
- {??
- ????if(libvlc_mp!=NULL){??
- ????????libvlc_media_player_stop?(libvlc_mp);??
- ????????libvlc_media_player_release?(libvlc_mp);??
- ????????KillTimer(1);??
- ????}??
- ??????
- ????SystemClear();??
- }??
?
视频播放进度杂时间轴的显示
随着视频的播放,需要在视频播放进度的时间轴上更新播放进度信息。在程序中使用了一个定时器完成这个功能。
在视频开始播放的时候,调用SetTimer()开启定时器。时间间隔设置为1000ms。
[cpp]
view plaincopy
- SetTimer(1,1000,NULL);??
在视频停止播放的时候,调用KillTimer()结束定时器。
[cpp]
view plaincopy
- KillTimer(1);??
在定时器的消息响应函数中,调用libvlc_media_player_get_time()获取当前视频的播放进度,此外调用libvlc_media_player_get_length()获取视频的总时长。
经过计算之后,就可以把计算的结果设置到相应的编辑框(Edit Control)以及滑动控制条(Slider Control)上。
[cpp]
view plaincopy
- 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()设定视频的播放进度。消息响应函数中的代码如下所示。
[cpp]
view plaincopy
- 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将中文解析为乱码从而导致无法播放的问题。这个问题卡了 我一阵子时间。造成这一问题的原因在于VLC的输入文件路径是使用UTF-8编码的。因此我们需要将输入路径转码为UTF-8编码。转码之后这一问题即得 到了解决。
Unicode转码为UTF-8的函数代码如下所示。
[cpp]
view plaincopy
- 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;??
? }??