Qt音視訊開發5-vlc事件訂閱
阿新 • • 發佈:2020-08-07
一、前言
事件訂閱可以拿到檔案長度、播放進度、播放狀態改變等資訊,vlc的事件訂閱機制封裝的比較友好,只需要先建立一個事件管理器,然後逐個訂閱自己感興趣的需要的事件,不感興趣的可以不要訂閱,只有訂閱了的事件才能在事件回撥中拿到,所以如果在事件回撥中發現一些事件沒有拿到,首先要檢查下到底訂閱了沒有,所有事件的列舉在libvlc_events.h標頭檔案中可以查閱到,都用的是通俗易懂的全英文單詞描述,有過基本英語能力的開發人員都能看懂。
在呼叫libvlc_event_attach訂閱事件的時候,第三個引數指定事件回撥函式,第四個引數傳入使用者資料,一般是用來傳入類的指標,這樣在事件回撥的時候,可以直接拿到並轉換為類指標,然後使用類中的方法,在對Qt4-Qt5的相容過程中發現,Qt5中的訊號是public的,所以可以直接在回撥函式中emit傳送訊號,而Qt4中的訊號是protected的,沒法直接emit,所以需要做一個通用的中轉函式,用來重新分發訊號,通過引數type來控制型別,QVariantList來傳入引數集合。
二、功能特點
- 多執行緒實時播放視訊流和本地視訊。
- 支援windows+linux+mac,支援vlc2和vlc3。
- 多執行緒顯示影象,不卡主介面。
- 自動重連網路攝像頭。
- 可設定邊框大小即偏移量和邊框顏色。
- 可設定是否繪製OSD標籤即標籤文字或圖片和標籤位置。
- 可設定兩種OSD位置和風格。
- 可設定是否儲存到檔案以及檔名。
- 可直接拖曳檔案到vlcwidget控制元件播放。
- 支援h265視訊流+rtmp等常見視訊流。
- 可暫停播放和繼續播放。
- 支援回撥模式和控制代碼兩種模式。
- 支援執行緒讀取進度等資訊和事件回撥兩種處理模式。
- 自動將當前播放位置和音量大小是否靜音以訊號發出去。
- 提供介面設定播放位置和音量及設定靜音。
- 支援儲存單個視訊檔案和定時儲存視訊檔案。
- 自定義頂部懸浮條,傳送單擊訊號通知,可設定是否啟用。
三、效果圖
四、相關站點
- 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
- 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
- 個人主頁:https://blog.csdn.net/feiyangqingyun
- 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
- 體驗地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652
五、核心程式碼
//事件回撥
static void handleEvents(const libvlc_event_t *event, void *userData)
{
VlcThread *thread = (VlcThread *)userData;
switch (event->type) {
case libvlc_MediaPlayerLengthChanged: {
quint64 length = event->u.media_player_length_changed.new_length;
if (length > 0) {
thread->doEvent(1, QVariantList() << length);
qDebug() << TIMEMS << "檔案總長: " << length;
}
}
break;
case libvlc_MediaPlayerTimeChanged: {
quint64 position = event->u.media_player_time_changed.new_time;
if (position > 0) {
thread->doEvent(2, QVariantList() << position);
//qDebug() << TIMEMS << "當前時間: " << position;
}
}
break;
case libvlc_MediaPlayerPositionChanged: {
float position = event->u.media_player_position_changed.new_position;
if (position > 0) {
//qDebug() << TIMEMS << "當前進度: " << position;
}
}
break;
case libvlc_MediaParsedChanged:
qDebug() << TIMEMS << "媒體資訊: " << event->u.media_parsed_changed.new_status;
break;
//qDebug() << TIMEMS << "狀態改變: " << event->u.media_state_changed.new_state;
case libvlc_MediaPlayerOpening:
qDebug() << TIMEMS << "狀態改變: " << "libvlc_MediaPlayerOpening";
break;
case libvlc_MediaPlayerPlaying:
qDebug() << TIMEMS << "狀態改變: " << "libvlc_MediaPlayerPlaying";
break;
case libvlc_MediaPlayerPaused:
qDebug() << TIMEMS << "狀態改變: " << "libvlc_MediaPlayerPaused";
break;
case libvlc_MediaPlayerStopped:
qDebug() << TIMEMS << "狀態改變: " << "libvlc_MediaPlayerStopped";
break;
case libvlc_MediaPlayerEndReached: {
thread->doEvent(0, QVariantList());
qDebug() << TIMEMS << "狀態改變: " << "libvlc_MediaPlayerEndReached";
}
break;
default:
break;
}
}
//訂閱事件
static void libvlc_event_new(libvlc_event_manager_t *vlcEvent, VlcThread *thread)
{
//逐個訂閱自己感興趣的需要的事件
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerLengthChanged, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerTimeChanged, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerPositionChanged, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaParsedChanged, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerOpening, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerPlaying, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerPaused, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerStopped, handleEvents, thread);
libvlc_event_attach(vlcEvent, libvlc_MediaPlayerEndReached, handleEvents, thread);
}
//反訂閱事件
static void libvlc_event_release(libvlc_event_manager_t *vlcEvent, VlcThread *thread)
{
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerLengthChanged, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerTimeChanged, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerPositionChanged, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaParsedChanged, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerOpening, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerPlaying, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerPaused, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerStopped, handleEvents, thread);
libvlc_event_detach(vlcEvent, libvlc_MediaPlayerEndReached, handleEvents, thread);
}