1. 程式人生 > 實用技巧 >Qt音視訊開發5-vlc事件訂閱

Qt音視訊開發5-vlc事件訂閱

一、前言

事件訂閱可以拿到檔案長度、播放進度、播放狀態改變等資訊,vlc的事件訂閱機制封裝的比較友好,只需要先建立一個事件管理器,然後逐個訂閱自己感興趣的需要的事件,不感興趣的可以不要訂閱,只有訂閱了的事件才能在事件回撥中拿到,所以如果在事件回撥中發現一些事件沒有拿到,首先要檢查下到底訂閱了沒有,所有事件的列舉在libvlc_events.h標頭檔案中可以查閱到,都用的是通俗易懂的全英文單詞描述,有過基本英語能力的開發人員都能看懂。

在呼叫libvlc_event_attach訂閱事件的時候,第三個引數指定事件回撥函式,第四個引數傳入使用者資料,一般是用來傳入類的指標,這樣在事件回撥的時候,可以直接拿到並轉換為類指標,然後使用類中的方法,在對Qt4-Qt5的相容過程中發現,Qt5中的訊號是public的,所以可以直接在回撥函式中emit傳送訊號,而Qt4中的訊號是protected的,沒法直接emit,所以需要做一個通用的中轉函式,用來重新分發訊號,通過引數type來控制型別,QVariantList來傳入引數集合。

二、功能特點

  1. 多執行緒實時播放視訊流和本地視訊。
  2. 支援windows+linux+mac,支援vlc2和vlc3。
  3. 多執行緒顯示影象,不卡主介面。
  4. 自動重連網路攝像頭。
  5. 可設定邊框大小即偏移量和邊框顏色。
  6. 可設定是否繪製OSD標籤即標籤文字或圖片和標籤位置。
  7. 可設定兩種OSD位置和風格。
  8. 可設定是否儲存到檔案以及檔名。
  9. 可直接拖曳檔案到vlcwidget控制元件播放。
  10. 支援h265視訊流+rtmp等常見視訊流。
  11. 可暫停播放和繼續播放。
  12. 支援回撥模式和控制代碼兩種模式。
  13. 支援執行緒讀取進度等資訊和事件回撥兩種處理模式。
  14. 自動將當前播放位置和音量大小是否靜音以訊號發出去。
  15. 提供介面設定播放位置和音量及設定靜音。
  16. 支援儲存單個視訊檔案和定時儲存視訊檔案。
  17. 自定義頂部懸浮條,傳送單擊訊號通知,可設定是否啟用。

三、效果圖

四、相關站點

  1. 國內站點:https://gitee.com/feiyangqingyun/QWidgetDemo
  2. 國際站點:https://github.com/feiyangqingyun/QWidgetDemo
  3. 個人主頁:https://blog.csdn.net/feiyangqingyun
  4. 知乎主頁:https://www.zhihu.com/people/feiyangqingyun/
  5. 體驗地址: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);
}