天天看點

Qt開源作品1-視訊流播放ffmpeg核心

一、前言

好久以前就寫過這個工具,後來因為Qt版本的不斷更新以及ffmpeg也經曆過好多次的疊代,可能從官網下載下傳的ffmpeg搭配原來的代碼不能正确編譯,因為很多api已經變了,是以這次特意抽空全部整理重寫一遍,隻求最精簡最好用,同時相容了ffmpeg3和ffmpeg4,并且同時支援32位的庫和64位的庫,這樣任何小白拿過去直接編譯就能用。

  1. 多線程實時繪制
  2. 同時解碼視訊流和音頻流
  3. 支援任意Qt版本任意系統任意編譯器
  4. 解碼和窗體分離,拓展性強
  5. 可選ffmpeg3和ffmpeg4兩個版本
  6. 可選32位和64位的ffmpeg庫
  7. 注釋絕對詳細,包你滿意

二、代碼思路

第一步:引入ffmpeg的頭檔案

//必須加以下内容,否則編譯不能通過,為了相容C和C99标準
#ifndef INT64_C
#define INT64_C
#define UINT64_C
#endif

//引入ffmpeg頭檔案
extern "C" {
#include "libavutil/opt.h"
#include "libavutil/time.h"
#include "libavutil/frame.h"
#include "libavutil/pixdesc.h"
#include "libavutil/avassert.h"
#include "libavutil/imgutils.h"
#include "libavutil/ffversion.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
#include "libavfilter/avfilter.h"

#ifdef ffmpegdevice
#include "libavdevice/avdevice.h"
#endif

#ifndef gcc45
#include "libavutil/hwcontext.h"
#include "libavutil/hwcontext_qsv.h"
#endif
}           

第二步:注冊ffmpeg的庫

這裡發現很多人每個類都注冊一次,搞得記憶體每次增加很多,不是不可以,而是沒有必要,其實ffmpeg的庫和解碼器等,在一個程式中隻需要注冊一次即可,沒必要每個視訊類都注冊一次。

//一個軟體中隻需要初始化一次就行
void FFmpegThread::initlib()
{
    static QMutex mutex;
    QMutexLocker locker(&mutex);
    static bool isInit = false;
    if (!isInit) {
        //注冊庫中所有可用的檔案格式和解碼器
        av_register_all();
        //注冊所有裝置,主要用于本地錄影機播放支援
#ifdef ffmpegdevice
        avdevice_register_all();
#endif
        //初始化網絡流格式,使用網絡流時必須先執行
        avformat_network_init();

        isInit = true;
        qDebug() << TIMEMS << "init ffmpeg lib ok" << " version:" << FFMPEG_VERSION;
#if 0
        //輸出所有支援的解碼器名稱
        QStringList listCodeName;
        AVCodec *code = av_codec_next(NULL);
        while (code != NULL) {
            listCodeName << code->name;
            code = code->next;
        }

        qDebug() << TIMEMS << listCodeName;
#endif
    }
}           

第三步:設定參數

//在打開碼流前指定各種參數比如:探測時間/逾時時間/最大延時等
//設定緩存大小,1080p可将值調大
av_dict_set(&options, "buffer_size", "8192000", 0);
//以tcp方式打開,如果以udp方式打開将tcp替換為udp
av_dict_set(&options, "rtsp_transport", "tcp", 0);
//設定逾時斷開連接配接時間,機關微秒,3000000表示3秒
av_dict_set(&options, "stimeout", "3000000", 0);
//設定最大時延,機關微秒,1000000表示1秒
av_dict_set(&options, "max_delay", "1000000", 0);
//自動開啟線程數
av_dict_set(&options, "threads", "auto", 0);           

第四步:打開視訊流

具體代碼比較多,詳細代碼請自行開源首頁下載下傳。

第五步:解碼圖像

void FFmpegThread::run()
{
    //計時
    QTime time;
    while (!stopped) {
        //根據标志位執行初始化操作
        if (isPlay) {
            this->init();
            isPlay = false;
            continue;
        }

        time.restart();
        if (av_read_frame(avFormatContext, avPacket) >= 0) {
            //判斷目前包是視訊還是音頻
            int packetSize = avPacket->size;
            int index = avPacket->stream_index;
            if (index == videoStreamIndex) {
                //解碼視訊流
                avcodec_decode_video2(videoCodec, avFrame2, &frameFinish, avPacket);

                if (frameFinish) {
                    //将資料轉成一張圖檔
                    sws_scale(swsContext, (const uint8_t *const *)avFrame2->data, avFrame2->linesize, 0, videoHeight, avFrame3->data, avFrame3->linesize);

                    //以下兩種方法都可以
                    //QImage image(avFrame3->data[0], videoWidth, videoHeight, QImage::Format_RGB32);
                    QImage image((uchar *)buffer, videoWidth, videoHeight, QImage::Format_RGB32);
                    if (!image.isNull()) {
                        emit receiveImage(image);
                    }

                    msleep(1);
                }
            } else if (index == audioStreamIndex) {
                //解碼音頻流,這裡暫不處理,以後交給sdl播放
            }
        }

        av_packet_unref(avPacket);
        av_freep(avPacket);
        msleep(1);
    }

    //線程結束後釋放資源
    free();
    stopped = false;
    isPlay = false;
    qDebug() << TIMEMS << "stop ffmpeg thread";
}           

三、效果圖

Qt開源作品1-視訊流播放ffmpeg核心

四、開源首頁

以上作品完整源碼下載下傳都在開源首頁,會持續不斷更新作品數量和品質,歡迎各位關注。

  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/

繼續閱讀