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 );
            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
[email protected]
https://ffmpeg.org/mailman/listinfo/ffmpeg-user

To unsubscribe, visit link above, or email
[email protected] with subject "unsubscribe".

Reply via email to