支持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 
#include 
#include 
#include 
#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
//写视频帧
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一样是线程安全的,如果希望线程安全需要自己改写!



你可能感兴趣的:(Opencv)