本文來自於: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"下的視頻,實際使用的代碼如下所示。
libvlc_media_new_location (inst, "file:///F:\\movie\\cuc_ieschool.flv");
此外,VLC還支持很多"神奇"的協議,比如輸入"screen://"協議就可以進行屏幕錄制,代碼如下。
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) 開啟定時器,用於更新視頻播放的進度(后文詳細記錄)
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將中文解析為亂碼從而導致無法播放的問題。這個問題卡了 我一陣子時間。造成這一問題的原因在於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; }