如何解决使用 h264 将 .png 图像编码为磁盘上的文件
有人可以帮我找出为什么我在将有效的 YUV 图像发送到编解码器的同时,磁盘上的文件只有 24 kb 并且无法通过 vlc 左右读取。我添加了 .h 和 .cpp 文件。直到“avcodec_receive_packet”一切似乎都没问题。函数调用“avcodec_send_frame”返回0,所以一定没问题,但“avcodec_receive_packet”返回-11。如果我刷新编码器(当前已注释),则“avcodec_receive_packet”返回 0,如果我将其存储在磁盘上,我可以看到编码数据。此外,编码器的输入图像也是正确的(当前已注释)并已检查。我的目标是帧内编码,所以我应该取回编码的帧数据,但即使我向它发送 24 个图像,我也没有取回任何东西。
.h 文件
#ifndef MOVIECODEC_H
#define MOVIECODEC_H
#include <cv.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/libavutil/imgutils.h"
#include "Codec/include/libswscale/swscale.h"
}
class MovieCodec
{
public:
MovieCodec(const char *filename);
~MovieCodec();
void encodeImage( const cv::Mat& image );
void close();
private :
void add_stream();
void openVideoCodec();
void write_video_frame(const cv::Mat& image);
void createFrame( const cv::Mat& image );
private:
static int s_frameCount;
int m_timeVideo = 0;
std::string m_filename;
FILE* m_file;
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;
};
.cpp 文件
#ifndef MOVIECODEC_CPP
#define MOVIECODEC_CPP
#include "moviecodec.h"
#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 */
static int sws_flags = SWS_BICUBIC;
int MovieCodec::s_frameCount = 0;
MovieCodec::MovieCodec( const char* filename ) :
m_filename( filename ),m_encoder( avcodec_find_encoder( AV_CODEC_ID_H264 ))
{
av_log_set_level(AV_LOG_VERBOSE);
int ret(0);
m_file = fopen( m_filename.c_str(),"wb");
// 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();
av_dump_format( m_formatCtx,m_filename.c_str(),1);
// Open the output media file,if needed
if (!( m_outputFormat->flags & AVFMT_NOFILE))
{
ret = avio_open( &m_formatCtx->pb,AVIO_FLAG_WRITE);
if (ret < 0)
{
char error[255];
ret = av_strerror( ret,error,255);
fprintf(stderr,"Could not open '%s': %s\n",error);
return ;
}
}
else
{
return;
}
m_formatCtx->flush_packets = 1;
ret = avformat_write_header( m_formatCtx,NULL );
if (ret < 0)
{
char error[255];
av_strerror(ret,255);
fprintf(stderr,"Error occurred when opening output file: %s\n",error);
return;
}
if ( m_frame )
m_frame->pts = 0;
}
MovieCodec::~MovieCodec()
{
close();
}
void MovieCodec::encodeImage(const cv::Mat &image)
{
// Compute video time from last added video frame
m_timeVideo = (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 );
// Increase frame pts according to time base
m_frame->pts += av_rescale_q(1,m_codecCtx->time_base,m_streamOut->time_base);
}
void MovieCodec::close()
{
int ret( 0 );
// Write media trailer
// if( m_formatCtx )
// ret = av_write_trailer( m_formatCtx );
/* flush the encoder */
ret = avcodec_send_frame(m_codecCtx,NULL);
/* Close each codec. */
if ( m_streamOut )
{
av_free( m_frame->data[0]);
av_free( m_frame );
}
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( m_file );
}
void MovieCodec::createFrame( const cv::Mat& image )
{
/**
* \note allocate frame
*/
m_frame = av_frame_alloc();
m_frame->format = STREAM_PIX_FMT;
m_frame->width = image.cols();
m_frame->height = image.rows();
m_frame->pict_type = AV_PICTURE_TYPE_I;
int 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.cols(),(int)image.rows(),AV_PIX_FMT_RGB24,(int)image.cols(),NULL);
const uint8_t* rgbData[1] = { (uint8_t* )image.getData() };
int rgbLinesize[1] = { 3 * image.cols() };
sws_scale(sws_ctx,rgbData,rgbLinesize,image.rows(),m_frame->data,m_frame->linesize);
}
/* Add an output stream. */
void MovieCodec::add_stream()
{
AVCodecID codecId = AV_CODEC_ID_H264;
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);
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->codecpar->codec_tag = 0x31637661;
m_streamOut->codecpar->video_delay = 0;
m_streamOut->time_base = { 1,STREAM_FRAME_RATE };
avcodec_parameters_to_context( m_codecCtx,m_streamOut->codecpar);
m_codecCtx->gop_size = 0; /* emit one intra frame every twelve frames at most */
m_codecCtx->max_b_frames = 0;
m_codecCtx->time_base = { 1,STREAM_FRAME_RATE };
m_codecCtx->framerate = { STREAM_FRAME_RATE,1 };
m_codecCtx->pix_fmt = STREAM_PIX_FMT;
if (m_streamOut->codecpar->codec_id == AV_CODEC_ID_H264)
{
av_opt_set( m_codecCtx,"preset","ultrafast",0 );
av_opt_set( m_codecCtx,"vprofile","baseline","tune","zerolatency",0 );
}
// /* Some formats want stream headers to be separate. */
// if (m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
// m_codecCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
void MovieCodec::openVideoCodec()
{
int ret;
/* open the codec */
ret = avcodec_open2(m_codecCtx,m_encoder,NULL);
if (ret < 0)
{
char error[255];
av_strerror(ret,"Could not open video codec: %s\n",error);
}
}
void MovieCodec::write_video_frame( const cv::Mat& image )
{
int ret;
createFrame( image );
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 */
//cv::Mat yuv420p( m_frame->height + m_frame->height/2,CV_8UC1,m_frame->data[0]);
//cv::Mat cvmIm;
//cv::cvtColor(yuv420p,cvmIm,CV_YUV420p2BGR);
//cv::imwrite("c:\\tmp\\YUVoriginal.png",cvmIm);
ret = avcodec_send_frame(m_codecCtx,m_frame);
if (ret < 0)
{
char error[255];
av_strerror(ret,"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);
do
{
ret = avcodec_receive_packet(m_codecCtx,&pkt);
if (ret == 0)
{
ret = av_write_frame( m_formatCtx,&pkt );
av_packet_unref(&pkt);
break;
}
// else if ((ret < 0) && (ret != AVERROR(EAGAIN)))
// {
// return;
// }
// else if (ret == AVERROR(EAGAIN))
// {
// /* flush the encoder */
// ret = avcodec_send_frame(m_codecCtx,NULL);
//
// if (0 > ret)
// return;
// }
} while (ret == 0);
if( !ret && pkt.size)
{
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 while writing video frame: %s\n",error);
return;
}
s_frameCount++;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。