【问题标题】:How to create grayscale video with avconv?如何使用 avconv 创建灰度视频?
【发布时间】:2016-06-20 13:11:50
【问题描述】:

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

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

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

【问题讨论】:

    标签: c++ opencv avconv


    【解决方案1】:

    为了完成这项任务,我找到的符合我需要的选项之一是以下类:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 2017-09-27
      相关资源
      最近更新 更多