Qt音視頻開發1-vlc解碼播放


一、前言

最開始接觸視頻監控這塊的時候,用的就是vlc作為解碼的內核,主要是因為vlc使用簡單方便,直接傳入一個句柄即可,簡單幾行代碼就可以實現一個視頻流播放,很適合初學者使用,也推薦初學者用qt+vlc來做播放器,提供的接口還是非常友好的,而且門類特別多,想要獲取媒體文件的各種信息比如寬高,設置寬高比等,直接調用接口函數傳入參數就能設置。

所有用vlc做視頻監控解碼的人都會遇到一個問題,那就是鼠標事件被接管攔截了,不能識別鼠標事件,比如雙擊最大化等,這就很憋屈了,明明很好用的一個東西,怎么突然之間鼠標事件也識別不到了呢,網上一搜一大把,主要有三個解決辦法。

  1. 修改vlc源碼,重新編譯,替換動態庫文件。
  2. 全局鼠標鈎子攔截鼠標消息進行處理。
  3. 設置句柄以后直接將控件/接受視頻渲染的控件禁用掉。

最終采用方法3,實現起來簡單快速,修改vlc源碼的編譯工作量太大了,畢竟vlc依賴一大堆的插件,用vlc的人一般都是初學者半吊子,哪里有能力去編譯一遍vlc哦。

二、功能特點

  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

五、核心代碼

bool VlcThread::init()
{
    //判斷該攝像機是否能聯通
    if (checkConn && isRtsp) {
        if (!checkUrl(url, checkTime)) {
            return false;
        }
    }

    QFileInfo info(url);
    suffix = info.suffix();

    //設置拓展名
    if (url.startsWith("dshow://")) {
        suffix = "dshow";
    } else if (url.startsWith("rtsp")) {
        suffix = "rtsp";
    } else if (url.startsWith("rtmp")) {
        suffix = "rtmp";
    } else if (url.startsWith("http")) {
        suffix = "http";
    }

    const char *tempArg = "";
    if (suffix == "h264") {
        tempArg = "--demux=h264";
    } else if (suffix == "h265") {
        tempArg = "--demux=h265";
    }

    const char *vlc_args[9] = {"-I", "dummy", "--no-osd", "--no-stats", "--ignore-config", "--no-video-on-top", "--no-video-title-show", "--no-snapshot-preview", tempArg};
    vlcInst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    if (vlcInst == NULL) {
        return false;
    }

    if (isRtsp || suffix == "dshow") {
        vlcMedia = libvlc_media_new_location(vlcInst, url.toUtf8().constData());
    } else {
        //windows上需要替換文件路徑
        QString url = this->url;
        url = QDir::toNativeSeparators(url);
        vlcMedia = libvlc_media_new_path(vlcInst, url.toUtf8().constData());
    }

    if (vlcMedia == NULL) {
        return false;
    }

    //媒體播放對象
    vlcPlayer = libvlc_media_player_new_from_media(vlcMedia);
    if (vlcPlayer == NULL) {
        return false;
    }

    //創建事件管理器
    if (callbackevent) {
        vlcEvent = libvlc_media_player_event_manager(vlcPlayer);
        libvlc_event_new(vlcEvent, this);
    }

    //回調方式和句柄方式兩種分別處理
    if (callback) {
        callbackData = new CallbackData;
        callbackData->thread = this;
        callbackData->pixels = new uchar[bufferWidth * bufferHeight * 4];
        memset(callbackData->pixels, 0, bufferWidth * bufferHeight * 4);

        int width = callbackData->thread->getBufferWidth();
        int height = callbackData->thread->getBufferHeight();

        //設置回調拿到每幀數據
        libvlc_video_set_callbacks(vlcPlayer, lock, unlock, display, callbackData);
        //設置每幀格式 RV32-Format_RGB32  RGBA-Format_RGBA8888 YUYV I420
        libvlc_video_set_format(vlcPlayer, "RV32", width, height, width * 4);
    } else {
        //設置播放句柄
        if (playWidget == NULL) {
            return false;
        }

#if defined(Q_OS_WIN)
        libvlc_media_player_set_hwnd(vlcPlayer, (void *)playWidget->winId());
#elif defined(Q_OS_LINUX)
        libvlc_media_player_set_xwindow(vlcPlayer, playWidget->winId());
#elif defined(Q_OS_MAC)
        libvlc_media_player_set_nsobject(vlcPlayer, (void *)playWidget->winId());
#endif

        //禁用句柄鼠標消息
        QTimer::singleShot(1000, this, SLOT(disableHwnd()));
    }

    //設置硬件加速 none auto any d3d11va dxva2
    setOption(QString(":avcodec-hw=%1").arg(hardware));
    //設置通信協議 tcp udp
    setOption(QString(":rtsp-%1").arg(transport));
    //設置緩存時間 默認500毫秒
    setOption(QString(":network-caching=%1").arg(caching));
    //:rtsp-frame-buffer-size=1000000

    //設置寬度高度,本地USB攝像頭需要單獨設置
    if (suffix == "dshow") {
        setOption(QString(":dshow-size=%1*%2").arg(videoWidth).arg(videoHeight));
    } else {
        setSize(videoWidth, videoHeight);
    }

    //設置保存文件
    this->initSave();
    //打開播放
    libvlc_media_player_play(vlcPlayer);

    //qDebug() << TIMEMS << "init vlc finsh";
    return true;
}


免責聲明!

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



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