Qt音視頻開發37-USB攝像頭解碼ffmpeg方案


一、前言

用ffmpeg來處理USB攝像頭,是前段時間研究視頻監控ffmpeg內核的時候搞定的,既然ffmpeg這么牛逼的庫可以解析各種音視頻,我想處理個本地USB攝像頭應該也不是什么難事,果真搜索也是一大堆,當然主要也是因為有個項目的應用需要用到ffmpeg來處理本地USB攝像頭,需要拿到每張圖片做智能分析,用Qt自帶的camera類不大好處理,剛好將ffmpeg的處理流程都搞清楚了,索性直接用ffmpeg來直接處理好了,用上這么強大的解碼庫,理論上支持各種USB攝像頭。本地USB攝像機不需要硬解碼,視頻流編碼類型為 AV_CODEC_ID_RAWVIDEO 像素格式為 AV_PIX_FMT_YUYV422 不經過解碼操作直接就可顯示。

ffmpeg方案處理流程:

  1. 引入avdevice.h頭文件,調用avdevice_register_all();注冊本地設備處理。
  2. 調用av_dict_set設置分辨率(video_size)、幀率(framerate)等參數。
  3. 調用av_find_input_format設置輸入格式。
  4. 調用avformat_open_input打開文件。
  5. 調用av_find_best_stream找到視頻流地址。
  6. 調用avcodec_find_decoder設置視頻解碼器。
  7. 調用av_read_frame循環解碼讀取幀數據。
  8. 調用avcodec_send_packet avcodec_receive_frame解碼數據。
  9. 處理完以后調用av_frame_free avcodec_close等釋放資源。

二、功能特點

  1. 同時支持windows、linux、嵌入式linux上的USB攝像頭實時采集。
  2. 支持多路USB攝像頭多線程實時采集。
  3. 在嵌入式linux設備上,自動查找USB設備文件並加載。
  4. 可手動設置設備文件名稱,手動設置后按照手動設置的設備文件加載。
  5. 在嵌入式linux設備上支持人臉識別接口,實時繪制人臉框。
  6. 具有打開、暫停、繼續、關閉、截圖等常規功能。
  7. 可設置兩路OSD標簽,分別設置文本、顏色、字號、位置等。
  8. 可作為視頻監控系統使用。

三、效果圖

四、相關站點

  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

五、核心代碼

void FFmpegThread::initOption()
{
    //在打開碼流前指定各種參數比如:探測時間/超時時間/最大延時等
    //設置緩存大小,1080p可將值調大
    av_dict_set(&options, "buffer_size", "8192000", 0);
    //以tcp方式打開,如果以udp方式打開將tcp替換為udp
    av_dict_set(&options, "rtsp_transport", transport.toUtf8().constData(), 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);

    //單獨對USB攝像機設置參數
    if (isUsbCamera) {
        //設置輸入格式
        //av_dict_set(&options, "input_format", "mjpeg", 0);
        //設置分辨率
        QString size = QString("%1x%2").arg(videoWidth).arg(videoHeight);
        av_dict_set(&options, "video_size", size.toUtf8().constData(), 0);
        //設置幀率
        av_dict_set(&options, "framerate", "25", 0);
    }

    //本地USB攝像機不需要硬解碼,強制改成回調運行和無硬解碼
    //視頻流編碼類型為 AV_CODEC_ID_RAWVIDEO 像素格式為 AV_PIX_FMT_YUYV422 不經過解碼操作直接就可顯示
    if (isUsbCamera) {
        callback = true;
        hardware = "none";
    }

    //沒有啟用opengl則強制改為回調
#ifndef opengl
    callback = true;
#endif

    //rtmp視頻流強制改成存儲成h264裸流,目前存儲成mp4還有問題
    if (url.startsWith("rtmp", Qt::CaseInsensitive)) {
        saveMp4 = false;
    }
}

bool FFmpegThread::initInput()
{
    //實例化格式處理上下文
    formatCtx = avformat_alloc_context();
    //設置超時回調,有些不存在的地址或者網絡不好的情況下要卡很久
    formatCtx->interrupt_callback.callback = AVInterruptCallBackFun;
    formatCtx->interrupt_callback.opaque = this;

    //必須要有tryOpen標志位來控制超時回調,由他來控制是否繼續阻塞等待打開
    tryOpen = false;

    //先判斷是否是本地設備(video=設備名字符串),打開的方式不一樣
    QByteArray urlData = url.toUtf8();
    AVInputFormat *ifmt = NULL;
    if (isUsbCamera) {
#if defined(Q_OS_WIN)
        ifmt = av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)
        //ifmt = av_find_input_format("v4l2");
        ifmt = av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)
        ifmt = av_find_input_format("avfoundation");
#endif
    }

    int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);
    tryOpen = true;
    if (result < 0) {
        qDebug() << TIMEMS << "open input error" << url;
        return false;
    }

    //釋放設置參數
    if (options != NULL) {
        av_dict_free(&options);
    }

    //獲取流信息
    result = avformat_find_stream_info(formatCtx, NULL);
    if (result < 0) {
        qDebug() << TIMEMS << "find stream info error";
        return false;
    }

    return true;
}


免責聲明!

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



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