支持opencv的Mat圖像採用x264等編碼器編碼的類

雖然在opencv中提供了videoWriter類可以將opencv圖像編碼成視頻,但是由於自帶的videoWriter支持的格式都是未經壓縮的,具體參考如下:

CV_FOURCC('P', 'I', 'M', '1') = MPEG-1 codec

CV_FOURCC('M', 'J', 'P', 'G') = motion-jpeg codec
CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec 
CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec 
CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec 
CV_FOURCC('U', '2', '6', '3') = H263 codec 
CV_FOURCC('I', '2', '6', '3') = H263I codec 

CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec

對於視覺開發末期經常需要將處理過後的視頻壓縮存儲,此時就需要藉助一些特定編碼器完成,opencv中視頻支持相關的都是採用ffmpeg完成的,而原本的opencv中並不支持所有的ffmpeg功能。所以一種方案是自己編譯opencv + ffmpeg,另一種就是自己使用對應編碼器完成編碼。

本文采用第二種方法,通過參考雷霄驊大神的代碼,自己封裝了一個可供opencv調用的視頻編碼類(videoEncode),類的接口和opencv的videoWriter比較類似,可以調用各種編碼器直接將Mat數據壓縮成avi封裝格式的視頻(理論上是可以各種封裝格式的,無奈沒有解決pts和dts的問題,其他格式播放過快)。

貼出部分代碼:

#ifndef VIDEOENCODER_H
#define VIDEOENCODER_H

#include <iostream>
#include <string>
#include <strstream>
#include <opencv.hpp>
#include "ffCodecs.hpp"

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
}

using namespace std;
using namespace cv;

typedef unsigned long long uInt64;
class videoEncoder
{
public:
    videoEncoder();
    videoEncoder(std::string filename, int codecID, double frameRate, int imgWidth, int imgHeight);   //編碼器和輸出文件名
    ~videoEncoder();
    bool isOpened();                                                //編碼器是否已經打開
    bool open(std::string filename, int codecID, double frameRate, int imgWidth, int imgHeight); //打開編碼器
    void setParam(int codecID, double frameRate, int imgWidth, int imgHeight);                    //設置參數
    void setBitrateControl(std::string controlMode, int bpsValue);         //碼流控制方式及大小
    void close();                                                   //關閉編碼器
    bool write(const Mat &frame);                                      //寫視頻

protected:
    void init();
    bool allocParamMem();               //爲編碼器參數分配空間
    std::string int2String(int interger);
    int flushEncoder(AVFormatContext *fmt_ctx,unsigned int stream_index);  //清空編碼器的緩衝區

    //設置編碼器
    int setCodec(char codec[4]);

private:
    AVFormatContext* pFormatCtx;        //
    AVOutputFormat* fmt;
    AVStream* video_st;
    AVCodecContext* pCodecCtx;
    AVCodec* pCodec;                    //編碼器格式,可自主指定,默認由封裝格式後綴名決定
    AVPacket pkt;                       //視頻幀packet

    //uint8_t* picture_buf;               //圖像buffer
    unsigned char* picture_buf;         //圖像buffer
    AVFrame* picture;
    int size;
    int y_size;                         //幀大小

    int bpsValue;                       //碼流控制方式的對應值
    int bpsMode;                        //碼流控制方式,0表示平均碼率(abr),1表示固定碼率(crf),2表示固定質量(cqp)

    cv::Mat image;                      //opencv中傳來待編碼的幀
    int img_width;                      //幀寬
    int img_height;                     //幀高
    std::string outputFileName;         //輸出文件名,由後綴決定封裝格式

    int fourcc;                         //編碼器的四字節碼
    double fps;                         //幀率
    uInt64 frameIndex;                   //當前幀序號

    bool isSetEncoderFlag;               //是否自設定編碼器
    bool isOpenedFlag;                  //編碼器是否已經打開

};

#endif // VIDEOENCODER_H
<pre name="code" class="cpp">//寫視頻幀
bool videoEncoder::write(const cv::Mat& frame)
{
    cv::Mat temp;
    cvtColor(frame,temp,COLOR_BGR2YUV_I420);

    picture_buf = temp.data;

    picture->data[0] = picture_buf;         //Y
    picture->data[1] = picture_buf+y_size;  //U
    picture->data[2] = picture_buf+(y_size*5/4);//V

    picture->pts = frameIndex++;
    int got_picture = 0;
    int ret = avcodec_encode_video2(pCodecCtx,&pkt,picture,&got_picture);
    if(ret<0)
    {
        printf("encode error!\n");
        return false;
    }
    if(got_picture==1)
    {
        pkt.stream_index = video_st->index;
        printf("pkt_pts:%d dts:%d\n",pkt.pts,pkt.dts);
        //ret = av_write_frame(pFormatCtx, &pkt);
        ret = av_interleaved_write_frame(pFormatCtx,&pkt);
        av_free_packet(&pkt);
    }
    return true;
}



完整工程(Qt工程,vs可以自己選取c文件和h,hpp文件建立):

videoEncoder

對於封裝成其他格式如MP4,flv,mkv時出現播放過快的問題沒有解決,希望知道的大神給與指點!同時該類並不是和opencv自帶的videoWriter一樣是線程安全的,如果希望線程安全需要自己改寫!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章