c++ - 缓冲的编码图像未保存
问题描述
我遇到了前 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
解决方案
推荐阅读
- sql - 如何划分两个查询
- git - `git branch -r` 输出中的 HEAD
- image - unity - 使用 tcp 套接字将图像从服务器传输到客户端。在代码更改方面需要帮助
- docker - docker 和 kubernetes 的正确代理设置是什么
- c++ - 奇怪的行为将 boost::geometry::within() 用于多边形和环
- wso2-am - WSO2 AM - 为 api 下载客户端 sdk 时,商店生成无效的 zip
- javascript - Reactjs objectlist groupby 和 map over
- c# - Fleck websocket 实现问题。无法使用套接字。发送
- linux - 使用 awk 忽略双引号
- javascript - 输入模式正则表达式