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

Paul B Mahol onemda at gmail.com
Wed Feb 10 14:39:32 EET 2021


On Wed, Feb 10, 2021 at 12:55 PM laddoe <xyfix at hotmail.com> 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 = 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(), (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(&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)
>         {
>             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 at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-user
>
> To unsubscribe, visit link above, or email
> ffmpeg-user-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-user mailing list