如何使用avconv创建灰度视频?

时间:2016-06-20 13:11:51

标签: c++ opencv avconv

我一直在寻找一些快速可靠的方法,用C ++应用程序中使用OpenCV捕获/创建的帧创建带有avconv库的灰度视频。

我知道OpenCV拥有创建视频的内部方式,但是它有一些编码性能和选项限制。

因此,通过这种方式,我想知道完成此任务的选项有哪些?

1 个答案:

答案 0 :(得分:0)

为完成此任务,我找到的符合我需求的选项之一是以下课程:

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
}
class AVConvVideoMaker
{
    AVCodec* codec;
    AVCodecContext* context;
    AVFrame* picture;
    int imgWidth, imgHeight, imgBufferSize;
    FILE* outputFile;
    int outputBufferSize;
    uint8_t* outputBuffer;
    int pictureBufferSize;
    uint8_t* pictureBuffer;
    int outputSize;

public:
    AVConvVideoMaker(std::string outputFilePath, int imgWidth, int imgHeight)
        : codec(NULL)
        , context(NULL)
        , picture(NULL)
        , imgWidth(imgWidth)
        , imgHeight(imgHeight)
        , imgBufferSize(imgWidth*imgHeight)
        , outputFile(fopen(outputFilePath.c_str(), "wb"))
        , outputBufferSize(100000)
        , outputBuffer(new uint8_t[outputBufferSize])
        , pictureBufferSize((imgBufferSize*3)/2)
        , pictureBuffer(new uint8_t[pictureBufferSize])
        , outputSize(0)
    {
        avcodec_register_all();

        this->codec = avcodec_find_encoder(CODEC_ID_MPEG1VIDEO);
        if (!this->codec)
        {
            throw std::runtime_error("Codec not found");
        }
        this->context = avcodec_alloc_context3(codec);
        this->picture = avcodec_alloc_frame();

        this->context->bit_rate = 400000;
        this->context->width = this->imgWidth;
        this->context->height = this->imgHeight;
        this->context->time_base = (AVRational){1, 25};
        this->context->gop_size = 10;
        this->context->max_b_frames = 1;
        this->context->pix_fmt = PIX_FMT_YUV420P;
        if(avcodec_open2(this->context, this->codec, NULL) < 0)
        {
            throw std::runtime_error("Could not open codec");
        }
        if(!this->outputFile)
        {
            throw std::runtime_error("Could not open video output file");
        }
        this->picture->data[0] = this->pictureBuffer;
        this->picture->data[1] = this->picture->data[0] + imgBufferSize;
        this->picture->data[2] = this->picture->data[1] + imgBufferSize / 4;
        this->picture->linesize[0] = this->imgWidth;
        this->picture->linesize[1] = this->imgWidth / 2;
        this->picture->linesize[2] = this->imgWidth / 2;
    }

    void insertFrame(cv::Mat1b& img)
    {
        fflush(stdout);

        /* Y */
        for(int y=0; y < this->context->height; y++)
        {
            for(int x=0; x < this->context->width; x++)
            {
                this->picture->data[0][y * picture->linesize[0] + x] = img.at<uchar>(y,x);
            }
        }

        /* Cb and Cr */
        for(int y=0; y < this->context->height/2; y++)
        {
            for(int x=0; x < this->context->width/2; x++)
            {
                this->picture->data[1][y * this->picture->linesize[1] + x] = 128;
                this->picture->data[2][y * this->picture->linesize[2] + x] = 128;
            }
        }
        this->outputSize = avcodec_encode_video(this->context, this->outputBuffer, this->outputBufferSize, this->picture);
        fwrite(this->outputBuffer, 1, outputSize, this->outputFile);
    }

    ~AVConvVideoMaker()
    {
        this->outputBuffer[0] = 0x00;
        this->outputBuffer[1] = 0x00;
        this->outputBuffer[2] = 0x01;
        this->outputBuffer[3] = 0xb7;
        fwrite(this->outputBuffer, 1, 4, this->outputFile);
        fclose(this->outputFile);

        avcodec_close(this->context);
        av_free(this->context);
        av_free(this->picture);

        delete outputBuffer;
        delete pictureBuffer;
    }

};

要在Ubuntu 16.04中进行编译,您必须链接:

g++ --std=c++11 main.cpp -lopencv_core -lopencv_highgui -lavutil -lavcodec