Re: [FFmpeg-user] h264 encoding of bgr images into .mp4 file with libav

2021-02-10 Thread Paul B Mahol
On Wed, Feb 10, 2021 at 12:55 PM laddoe  wrote:

> I'm trying to encode(h264) a series of .png into a mp4 file. A cv::Mat
> holds the png data (BGR) and that is converted to YUV420P which is then
> encoded and written to a .mp4 file. I have added a block statement in the
> code to store image on the disk (before encoding) and that image is correct
> so the frame holds the correct data before it gets passed. The
> avcodec_send_frame returns 0 so up to that point everything works. But I
> get an mp4 file of 1 MB and I can't open it with vlc. Below is a short
> summary of my code
>
>
> ecodec.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 = 40;//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(), (int)image.rows(),
> AV_PIX_FMT_YUV420P,
>  0, NULL, NULL, NULL);
>
> const uint8_t* rgbData[1] = { (uint8_t* )image.getData() };
> int rgbLineSize[1] = { 3 * image.cols() };
>
> sws_scale(sws_ctx, rgbData, rgbLineSize, 0, image.rows(), frame->data,
> frame->linesize);
>
> frame->pict_type = AV_PICTURE_TYPE_I;
>
> cv::Mat yuv420p(frame->height + frame->height/2, frame->width,
> 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(_codecContextOut);
> av_frame_free();
> av_packet_free( _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)
> {
> fwrite(pkt->data, 1, pkt->size, m_file );
>

You are writing raw encoded frames here.

You nowhere use mov muxer code for muxing.

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);
> }
> ___
> ffmpeg-user mailing list
> ffmpeg-user@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-user
>
> To unsubscribe, visit link above, or email
> ffmpeg-user-requ...@ffmpeg.org with subject "unsubscribe".
___
ffmpeg-user mailing list
ffmpeg-user@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
ffmpeg-user-requ...@ffmpeg.org with subject 

[FFmpeg-user] h264 encoding of bgr images into .mp4 file with libav

2021-02-10 Thread laddoe
I'm trying to encode(h264) a series of .png into a mp4 file. A cv::Mat holds 
the png data (BGR) and that is converted to YUV420P which is then encoded and 
written to a .mp4 file. I have added a block statement in the code to store 
image on the disk (before encoding) and that image is correct so the frame 
holds the correct data before it gets passed. The avcodec_send_frame returns 0 
so up to that point everything works. But I get an mp4 file of 1 MB and I can't 
open it with vlc. Below is a short summary of my code


ecodec.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 = 40;//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(), (int)image.rows(), 
AV_PIX_FMT_YUV420P,
 0, NULL, NULL, NULL);

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

sws_scale(sws_ctx, rgbData, rgbLineSize, 0, image.rows(), frame->data, 
frame->linesize);

frame->pict_type = AV_PICTURE_TYPE_I;

cv::Mat yuv420p(frame->height + frame->height/2, frame->width, 
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(_codecContextOut);
av_frame_free();
av_packet_free( _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)
{
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);
}
___
ffmpeg-user mailing list
ffmpeg-user@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
ffmpeg-user-requ...@ffmpeg.org with subject "unsubscribe".