基於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;   
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM