问题描述
我正在尝试将 (h264) 一系列 .png 编码为 mp4 文件。 cv::Mat 保存 png 数据 (BGR),然后将其转换为 YUV420P,然后将其编码并写入 .mp4 文件。我在代码中添加了两个块语句来将图像存储在磁盘上(编码前后)。编码前的第一个图像是正确的,但编码后的第二个图像不正确。 avcodec_send_frame 返回 0,所以到那时一切正常。 编辑:我得到一个 1 MB 的 mp4 文件,但我无法用 vlc 打开它 生态解码器.h
class ECodec
{
public:
MovieCodec();
~MovieCodec();
void MatToFrame( cv::Mat& image );
void encode( AVFrame *frame,AVPacket *pkt );
private:
FILE* m_file;
AVCodec* m_encoder = NULL;
AVCodecContext* m_codecContextout = NULL;
AVPacket* m_packet = NULL;
};
ecodec.cpp
ECodec::ECodec() :
// m_encoder( avcodec_find_encoder_by_name( videoCodec.c_str()))
m_encoder( avcodec_find_encoder( AV_CODEC_ID_H264 ))
{
m_file = fopen( "c:\\tmp\\outputVideo.mp4","wb");
}
void ECodec::MatToFrame( cv::Mat& image )
{
int ret( 0 );
int frameRate( 24 );
AVFrame *frame = NULL;
m_encoder( avcodec_find_encoder( AV_CODEC_ID_H264 ))
m_codecContextout = avcodec_alloc_context3( m_encoder );
m_codecContextout->width = 800;
m_codecContextout->height = 640;
m_codecContextout->bit_rate = 400000;//m_codecContextout->width * m_codecContextout->height * 3;
m_codecContextout->time_base = (AVRational){1,24};
m_codecContextout->framerate = (AVRational){24,1};
m_codecContextout->codec_tag = AV_CODEC_ID_H264;
m_codecContextout->pix_fmt = AV_PIX_FMT_YUV420P;
m_codecContextout->codec_type = AVMEDIA_TYPE_VIDEO;
m_codecContextout->gop_size = 1;
m_codecContextout->max_b_frames = 1;
av_log_set_level(AV_LOG_VERBOSE);
ret = av_opt_set(m_codecContextout->priv_data,"preset","slow",0);
ret = avcodec_open2(m_codecContextout,m_encoder,NULL);
frame = av_frame_alloc();
frame->format = AV_PIX_FMT_YUV420P;
frame->width = image.cols();
frame->height = image.rows();
ret = av_image_alloc(frame->data,frame->linesize,frame->width,frame->height,AV_PIX_FMT_YUV420P,1);
if (ret < 0)
{
return;
}
struct SwsContext *sws_ctx;
sws_ctx = sws_getContext((int)image.cols(),(int)image.rows(),AV_PIX_FMT_RGB24,(int)image.cols(),NULL,NULL);
const uint8_t* rgbData[1] = { (uint8_t* )image.getData() };
int rgbLinesize[1] = { 3 * image.cols() };
sws_scale(sws_ctx,rgbData,rgbLinesize,image.rows(),frame->data,frame->linesize);
frame->pict_type = AV_PICTURE_TYPE_I;
cv::Mat yuv420p(frame->height + frame->height/2,CV_8UC1,frame->data[0]);
cv::Mat cvmIm;
cv::cvtColor(yuv420p,cvmIm,CV_YUV420p2BGR);
cv::imwrite("c:\\tmp\\rawimage.png",cvmIm);
//OK
m_packet = av_packet_alloc();
ret = av_new_packet( m_packet,m_codecContextout->width * m_codecContextout->height * 3 );
/* encode the image */
encode( frame,m_packet );
avcodec_free_context(&m_codecContextout);
av_frame_free(&frame);
av_packet_free( &m_packet );
}
void ECodec::encode( AVFrame *frame,AVPacket *pkt )
{
int ret;
/* send the frame to the encoder */
ret = avcodec_send_frame( m_codecContextout,frame);
if (ret < 0)
{
fprintf(stderr,"Error sending a frame for encoding\n");
exit(1);
}
do
{
ret = avcodec_receive_packet(m_codecContextout,pkt);
if (ret == 0)
{
cv::Mat yuv420p(frame->height + frame->height/2,pkt->data);
cv::Mat cvmIm;
cv::cvtColor(yuv420p,CV_YUV420p2BGR);
cv::imwrite("c:\\tmp\\rawencodedimage.png",cvmIm);
//NOT OK
fwrite(pkt->data,1,pkt->size,m_file );
av_packet_unref(pkt);
break;
}
else if ((ret < 0) && (ret != AVERROR(EAGAIN)))
{
return;
}
else if (ret == AVERROR(EAGAIN))
{
ret = avcodec_send_frame(m_codecContextout,NULL);
if (0 > ret)
{
return;
}
}
} while (ret == 0);
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)