首页 > 解决方案 > 缓冲的编码图像未保存

问题描述

我遇到了前 12 张图像未保存到文件的问题。我已在本期附上相关文件。我还附加了一个日志文件,以显示前 12 个图像未写入生成的文件。帧速率为 24 fps,录制时间为 5 秒,因此应该有 120 帧写入输出文件。这可以在第 4 列中看到。日志文件中的行如下:

image num [来自相机的唯一 num] [用于记录 seq 的临时图像 num] [time in ms]

image 类实际上是 OpenCV 的 mat 类的一个简单包装器,带有一些额外的成员。我目前得到的输出文件大约是 10 MB,当我在 VLC 中打开它时,它不会运行 5 秒,但更像是 1 - 2 秒,但我可以看到我记录的任何内容。谁能向我解释为什么文件没有写入并且持续时间不是预期的 5 秒(减去 12 帧丢失)。如您所见,我尝试过使用“av_interleaved_write_frame”,但这没有帮助

xcodec.h

#ifndef XCODEC_H
#define XCODEC_H

#include "image/Image.h"

extern "C"
{
    #include "Codec/include/libavcodec/avcodec.h"
    #include "Codec/include/libavdevice/avdevice.h"
    #include "Codec/include/libavformat/avformat.h"
    #include "Codec/include/libavutil/avutil.h"
    #include "Codec/include/libavformat/avio.h"
    #include "Codec/include/libavutil/imgutils.h"
    #include "Codec/include/libavutil/opt.h"
    #include "Codec/include/libswscale/swscale.h"
}


class XCodec
{
public:

    XCodec(const char *filename);

    ~XCodec();

    void encodeImage( const Image& image );

    void encode( AVFrame *frame, AVPacket *pkt );

    void add_stream();

    void openVideoCodec();

    void write_video_frame(const Image &image);

    void createFrame( const Image& image );

    void close();

private:

    static int s_frameCount;

    int m_timeVideo = 0;

    std::string m_filename;


    AVCodec* m_encoder = NULL;

    AVOutputFormat* m_outputFormat = NULL;

    AVFormatContext* m_formatCtx = NULL;

    AVCodecContext* m_codecCtx = NULL;

    AVStream* m_streamOut = NULL;

    AVFrame* m_frame = NULL;

    AVPacket* m_packet = NULL;

};

#endif

xcodec.cpp

#include "XCodec.h"

#include <QDebug>


#define STREAM_DURATION   5.0
#define STREAM_FRAME_RATE 24
#define STREAM_NB_FRAMES  ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
#define STREAM_PIX_FMT    AV_PIX_FMT_YUV420P /* default pix_fmt */
#define OUTPUT_CODEC AV_CODEC_ID_H264

int XCodec::s_frameCount = 0;

XCodec::XCodec( const char* filename ) :
    m_filename( filename ),
    m_encoder( avcodec_find_encoder( OUTPUT_CODEC ))
{
    av_log_set_level(AV_LOG_VERBOSE);

    int ret(0);


    // allocate the output media context
    ret = avformat_alloc_output_context2( &m_formatCtx, m_outputFormat, NULL, m_filename.c_str());

    if (!m_formatCtx)
        return;

    m_outputFormat = m_formatCtx->oformat;

    // Add the video stream using H264 codec
    add_stream();

    // Open video codec and allocate the necessary encode buffers
    if (m_streamOut)
        openVideoCodec();

    // Print detailed information about input and output
    av_dump_format( m_formatCtx, 0, m_filename.c_str(), 1);

    // Open the output media file, if needed
    if (!( m_outputFormat->flags & AVFMT_NOFILE))
    {
        ret = avio_open( &m_formatCtx->pb, m_filename.c_str(), AVIO_FLAG_WRITE);

        if (ret < 0)
        {
            char error[255];
            ret = av_strerror( ret, error, 255);
            fprintf(stderr, "Could not open '%s': %s\n", m_filename.c_str(), error);
            return ;
        }
    }
    else
    {
        return;
    }

    // Write media header
    ret = avformat_write_header( m_formatCtx, NULL );

    if (ret < 0)
    {
        char error[255];
        av_strerror(ret, error, 255);
        fprintf(stderr, "Error occurred when opening output file: %s\n", error);
        return;
    }

    if ( m_frame )
           m_frame->pts = 0;
}



XCodec::~XCodec()
{}

/* Add an output stream. */
void XCodec::add_stream()
{
    AVCodecID codecId = OUTPUT_CODEC;

    if (!( m_encoder ))
    {
        fprintf(stderr, "Could not find encoder for '%s'\n",
            avcodec_get_name(codecId));
        return;
    }

    // Get the stream for codec
    m_streamOut = avformat_new_stream(m_formatCtx, m_encoder);

    if (!m_streamOut) {
        fprintf(stderr, "Could not allocate stream\n");
        return;
    }

    m_streamOut->id = m_formatCtx->nb_streams - 1;

    m_codecCtx = avcodec_alloc_context3( m_encoder);

    switch (( m_encoder)->type)
    {
    case AVMEDIA_TYPE_VIDEO:
        m_streamOut->codecpar->codec_id = codecId;
        m_streamOut->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
        m_streamOut->codecpar->bit_rate = 400000;
        m_streamOut->codecpar->width = 800;
        m_streamOut->codecpar->height = 640;
        m_streamOut->codecpar->format = STREAM_PIX_FMT;
        m_streamOut->time_base = { 1, STREAM_FRAME_RATE };

        avcodec_parameters_to_context( m_codecCtx, m_streamOut->codecpar);

        m_codecCtx->gop_size = 12; /* emit one intra frame every twelve frames at most */
        m_codecCtx->max_b_frames = 1;
        m_codecCtx->time_base = { 1, STREAM_FRAME_RATE };
        m_codecCtx->framerate = { STREAM_FRAME_RATE, 1 };
        m_codecCtx->pix_fmt = STREAM_PIX_FMT;
        m_codecCtx->profile = FF_PROFILE_H264_HIGH;

        break;

    default:
        break;
    }

    if (m_streamOut->codecpar->codec_id == OUTPUT_CODEC)
    {
      av_opt_set( m_codecCtx, "preset", "ultrafast", 0 );
    }

/
//    /* Some formats want stream headers to be separate. */
    if (m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
            m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;


    int ret = avcodec_parameters_from_context( m_streamOut->codecpar, m_codecCtx );

    if (ret < 0)
    {
        char error[255];
        av_strerror(ret, error, 255);
        fprintf(stderr, "avcodec_parameters_from_context returned (%d) - %s", ret, error);
        return;
    }
}


void XCodec::openVideoCodec()
{
    int ret;

    /* open the codec */
    ret = avcodec_open2(m_codecCtx, m_encoder, NULL);

    if (ret < 0)
    {
        char error[255];
        av_strerror(ret, error, 255);
        fprintf(stderr, "Could not open video codec: %s\n", error);
        return;
    }

    /* allocate and init a re-usable frame */
//    m_frame = av_frame_alloc();

}


void XCodec::encodeImage(const Image &image)
{
    // Compute video time from last added video frame
    m_timeVideo = image.timeStamp(); //(double)m_frame->pts) * av_q2d(m_streamOut->time_base);

    // Stop media if enough time
    if (!m_streamOut /*|| m_timeVideo >= STREAM_DURATION*/)
       return;


    // Add a video frame
    write_video_frame( image );

}


void XCodec::write_video_frame( const Image& image )
{
    int ret;

qDebug() << "image num " << image.uniqueImageNumber() << " " << s_frameCount;

    if ( s_frameCount >= STREAM_NB_FRAMES)
    {
        /* No more frames to compress. The codec has a latency of a few
         * frames if using B-frames, so we get the last frames by
         * passing the same picture again. */
        int p( 0 ) ;
    }
    else
    {
         createFrame( image );
    }

    // Increase frame pts according to time base
//    m_frame->pts += av_rescale_q(1, m_codecCtx->time_base, m_streamOut->time_base);
    m_frame->pts = int64_t( image.timeStamp()) ;


    if (m_formatCtx->oformat->flags & 0x0020 )
    {
        /* Raw video case - directly store the picture in the packet */
        AVPacket pkt;
        av_init_packet(&pkt);

        pkt.flags |= AV_PKT_FLAG_KEY;
        pkt.stream_index = m_streamOut->index;
        pkt.data = m_frame->data[0];
        pkt.size = sizeof(AVPicture);

//        ret = av_interleaved_write_frame(m_formatCtx, &pkt);
        ret = av_write_frame( m_formatCtx, &pkt );
    }
    else
    {
        AVPacket pkt;
        av_init_packet(&pkt);

        /* encode the image */
        ret = avcodec_send_frame(m_codecCtx, m_frame);

        if (ret < 0)
        {
            char error[255];
            av_strerror(ret, error, 255);
            fprintf(stderr, "Error encoding video frame: %s\n", error);
            return;
        }

        /* If size is zero, it means the image was buffered. */
        ret = avcodec_receive_packet(m_codecCtx, &pkt);

        if( !ret && pkt.size)
        {
qDebug() << "write frame " << m_frame->display_picture_number;
            pkt.stream_index = m_streamOut->index;

            /* Write the compressed frame to the media file. */
//            ret = av_interleaved_write_frame(m_formatCtx, &pkt);
            ret = av_write_frame( m_formatCtx, &pkt );
        }
        else
        {
            ret = 0;
        }
    }

    if (ret != 0)
    {
        char error[255];
        av_strerror(ret, error, 255);
        fprintf(stderr, "Error while writing video frame: %s\n", error);
        return;
    }

    s_frameCount++;
}


void XCodec::createFrame( const Image& image /*, AVFrame *m_frame, int frame_index, int width, int height*/)
{
    /**
     * \note allocate frame
     */
    m_frame = av_frame_alloc();
    int ret = av_frame_make_writable( m_frame );

    m_frame->format = STREAM_PIX_FMT;
    m_frame->width = image.width();
    m_frame->height = image.height();
//    m_frame->pict_type = AV_PICTURE_TYPE_I;
    m_frame->display_picture_number = image.uniqueImageNumber();

    ret = av_image_alloc(m_frame->data, m_frame->linesize, m_frame->width,  m_frame->height, STREAM_PIX_FMT, 1);

    if (ret < 0)
    {
        return;
    }

    struct SwsContext* sws_ctx = sws_getContext((int)image.width(), (int)image.height(), AV_PIX_FMT_RGB24,
                                                (int)image.width(), (int)image.height(), STREAM_PIX_FMT, 0, NULL, NULL, NULL);

    const uint8_t* rgbData[1] = { (uint8_t* )image.getData() };
    int rgbLineSize[1] = { 3 * image.width() };

    sws_scale(sws_ctx, rgbData, rgbLineSize, 0, image.height(), m_frame->data, m_frame->linesize);

//cv::Mat yuv420p( m_frame->height + m_frame->height/2, m_frame->width, CV_8UC1, m_frame->data[0]);
//cv::Mat cvmIm;
//cv::cvtColor(yuv420p,cvmIm,CV_YUV420p2BGR);
//std::ostringstream ss;
//ss << "c:\\tmp\\YUVoriginal_" << image.uniqueImageNumber() << ".png";
//cv::imwrite( ss.str().c_str(), cvmIm);
}


void XCodec::close()
{
    /* reset the framecount */
    s_frameCount = 0 ;

    int ret( 0 );

    /* flush the encoder */
    while( ret >= 0 )
        ret = avcodec_send_frame(m_codecCtx, NULL);

    // Write media trailer
    if( m_formatCtx )
        ret = av_write_trailer( m_formatCtx );

    /* Close each codec. */
    if ( m_streamOut )
    {
        if( m_frame )
        {
            av_free( m_frame->data[0]);
            av_frame_free( &m_frame );
        }

        if( m_packet )
            av_packet_free( &m_packet );
    }

    if (!( m_outputFormat->flags & AVFMT_NOFILE))
        /* Close the output file. */
        ret = avio_close( m_formatCtx->pb);


    /* free the stream */
    avformat_free_context( m_formatCtx );

    fflush( stdout );
}

图像.h

#ifndef IMAGE_H
#define IMAGE_H

#include <mat.hpp> 

class Image 
{
public:

    Image();

    Image( const cv::Mat& mat );

    Image(const Image& other) = default;

    Image(Image&& other) = default;

    ~Image();


    inline const cv::Mat& matrix() const{ return m_matrix; }

    inline const int uniqueImageNumber() const{ return m_uniqueId; }

    inline const int timeStamp() const { return m_timeStamp; }

    inline const int width() const { return m_matrix.cols(); }
    
    inline const int height() const { return m_matrix.rows(); }

private:

    cv::Mat   m_matrix;

    int       m_timeStamp;

    int       m_uniqueId;

};

#endif

日志文件

 image num  1725   0   0
 image num  1727   1   40
 image num  1729   2   84
 image num  1730   3   126
 image num  1732   4   169
 image num  1734   5   211
 image num  1736   6   259
 image num  1738   7   297
 image num  1740   8   340
 image num  1742   9   383
 image num  1744   10   425
 image num  1746   11   467
 image num  1748   12   511
 image num  1750   13   553
 write frame  1750
 image num  1752   14   600
 write frame  1752
 image num  1753   15   637
 write frame  1753
 image num  1755   16   680
 write frame  1755
 image num  1757   17   723
 write frame  1757
 image num  1759   18   766
 write frame  1759
 image num  1761   19   808
 write frame  1761
 image num  1763   20   854
 write frame  1763
 image num  1765   21   893
 write frame  1765
 image num  1767   22   937
 write frame  1767
 image num  1769   23   979
 write frame  1769
 image num  1770   24   1022
 write frame  1770
 image num  1772   25   1064
 write frame  1772
 image num  1774   26   1108
 write frame  1774
 image num  1776   27   1150
 write frame  1776
 image num  1778   28   1192
 write frame  1778
 image num  1780   29   1235
 write frame  1780
 image num  1782   30   1277
 write frame  1782
 image num  1784   31   1320
 write frame  1784
 image num  1786   32   1362
 write frame  1786
 image num  1787   33   1405
 write frame  1787
 image num  1789   34   1450
 write frame  1789
 image num  1791   35   1493
 write frame  1791
 image num  1793   36   1536
 write frame  1793
 image num  1795   37   1578
 write frame  1795
 image num  1797   38   1621
 write frame  1797
 image num  1799   39   1663
 write frame  1799
 image num  1801   40   1709
 write frame  1801
 image num  1803   41   1748
 write frame  1803
 image num  1805   42   1791
 write frame  1805
 image num  1807   43   1833
 write frame  1807
 image num  1808   44   1876
 write frame  1808
 image num  1810   45   1920
 write frame  1810
 image num  1812   46   1962
 write frame  1812
 image num  1814   47   2004
 write frame  1814
 image num  1816   48   2048
 write frame  1816
 image num  1818   49   2092
 write frame  1818
 image num  1820   50   2133
 write frame  1820
 image num  1822   51   2175
 write frame  1822
 image num  1824   52   2221
 write frame  1824
 image num  1826   53   2277
 write frame  1826
 image num  1828   54   2319
 write frame  1828
 image num  1830   55   2361
 write frame  1830
 image num  1832   56   2405
 write frame  1832
 image num  1833   57   2447
 write frame  1833
 image num  1835   58   2491
 write frame  1835
 image num  1837   59   2533
 write frame  1837
 image num  1839   60   2576
 write frame  1839
 image num  1841   61   2619
 write frame  1841
 image num  1843   62   2662
 write frame  1843
 image num  1845   63   2704
 write frame  1845
 image num  1847   64   2746
 write frame  1847
 image num  1849   65   2789
 write frame  1849
 image num  1851   66   2831
 write frame  1851
 image num  1852   67   2874
 write frame  1852
 image num  1854   68   2917
 write frame  1854
 image num  1856   69   2959
 write frame  1856
 image num  1858   70   3003
 write frame  1858
 image num  1860   71   3045
 write frame  1860
 image num  1862   72   3088
 write frame  1862
 image num  1864   73   3130
 write frame  1864
 image num  1866   74   3173
 write frame  1866
 image num  1868   75   3215
 write frame  1868
 image num  1870   76   3257
 write frame  1870
 image num  1872   77   3306
 write frame  1872
 image num  1873   78   3347
 write frame  1873
 image num  1875   79   3389
 write frame  1875
 image num  1877   80   3433
 write frame  1877
 image num  1879   81   3475
 write frame  1879
 image num  1883   82   3562
 write frame  1883
 image num  1885   83   3603
 write frame  1885
 image num  1887   84   3660
 write frame  1887
 image num  1889   85   3704
 write frame  1889
 image num  1891   86   3747
 write frame  1891
 image num  1893   87   3789
 write frame  1893
 image num  1895   88   3832
 write frame  1895
 image num  1897   89   3874
 write frame  1897
 image num  1899   90   3917
 write frame  1899
 image num  1900   91   3959
 write frame  1900
 image num  1902   92   4001
 write frame  1902
 image num  1904   93   4044
 write frame  1904
 image num  1906   94   4086
 write frame  1906
 image num  1908   95   4130
 write frame  1908
 image num  1910   96   4174
 write frame  1910
 image num  1912   97   4216
 write frame  1912
 image num  1914   98   4257
 write frame  1914
 image num  1915   99   4303
 write frame  1915
 image num  1918   100   4344
 write frame  1918
 image num  1919   101   4387
 write frame  1919
 image num  1922   102   4451
 write frame  1922
 image num  1924   103   4494
 write frame  1924
 image num  1926   104   4541
 write frame  1926
 image num  1927   105   4588
 write frame  1927
 image num  1931   106   4665
 write frame  1931
 image num  1933   107   4707
 write frame  1933
 image num  1935   108   4750
 write frame  1935
 image num  1937   109   4794
 write frame  1937
 image num  1939   110   4836
 write frame  1939
 image num  1941   111   4879
 write frame  1941
 image num  1943   112   4922
 write frame  1943
 image num  1945   113   4965
 write frame  1945
 image num  1947   114   5007
 write frame  1947
 image num  1948   115   5050
 write frame  1948
 image num  1950   116   5093
 write frame  1950
 image num  1952   117   5136
 write frame  1952
 image num  1954   118   5178
 write frame  1954
 image num  1956   119   5221
 write frame  1956
 MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
0, 8-bit
Not writing 'clli' atom. No content light level info.
Not writing 'mdcv' atom. Missing mastering metadata.
 2 seeks, 41 writeouts

标签: c++ffmpegh.264libavlibavcodec

解决方案


推荐阅读