Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FFMPEG H264 encode each single image

i encode currently a QImage from RGB888 to H264, but i want to encode each image (even if this is not the perfect way) by itself. Im able to encode the image, but its needed to send the same image 46 times. And i dont know what i do wrong (probably wrong config of the encode, but i cannot find the issue there).

Afterwards i decode this image and then convert it back to a QImage. I do this only for testing some other code.

avcodec_register_all();

AVCodec *nVidiaCodec = avcodec_find_encoder_by_name("h264_nvenc");
if (!nVidiaCodec)
{
    return false;
}

AVCodecContext* av_codec_context_ = NULL;
av_codec_context_ = avcodec_alloc_context3(nVidiaCodec);
if (!av_codec_context_)
{
    return false;
}

av_codec_context_->width = dst->width;
av_codec_context_->height = dst->height;
av_codec_context_->pix_fmt = AV_PIX_FMT_YUV420P;
av_codec_context_->gop_size = 1;
av_codec_context_->keyint_min = 0;
av_codec_context_->scenechange_threshold = 0;
av_codec_context_->bit_rate = 8000000;
av_codec_context_->time_base.den = 1;
av_codec_context_->time_base.num = 1;
av_codec_context_->refs = 0;
av_codec_context_->qmin = 1;
av_codec_context_->qmax = 1;
av_codec_context_->b_frame_strategy = 0;
av_codec_context_->max_b_frames = 0;
av_codec_context_->thread_count = 1;

av_opt_set(av_codec_context_, "preset", "slow", 0);
av_opt_set(av_codec_context_, "tune", "zerolatency", 0);

int ret = avcodec_open2(av_codec_context_, nVidiaCodec, NULL);
if (0 > ret)
{
    return false;
}

AVFrame *picture = av_frame_alloc();
picture->format = AV_PIX_FMT_RGB24;
picture->width = dst->width;
picture->height = dst->height;

ret = avpicture_fill((AVPicture *)picture, imgSrc.bits(), AV_PIX_FMT_RGB24, dst->width, dst->height);
if (0 > ret)
{
    return false;
}

AVFrame *tmp_picture = av_frame_alloc();
tmp_picture->format = AV_PIX_FMT_YUV420P;
tmp_picture->width = dst->width;
tmp_picture->height = dst->height;
ret = av_frame_get_buffer(tmp_picture, 32);

SwsContext *img_convert_ctx = sws_getContext(av_codec_context_->width, av_codec_context_->height, AV_PIX_FMT_RGB24, av_codec_context_->width, av_codec_context_->height, av_codec_context_->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
if (!img_convert_ctx)
{
    return false;
}
ret = sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, av_codec_context_->height, tmp_picture->data, tmp_picture->linesize);
if (0 > ret)
{
    return  false;
}

ret = avcodec_send_frame(av_codec_context_, tmp_picture);
if (0 > ret)
{
    return  false;
}

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
do 
{
    ret = avcodec_receive_packet(av_codec_context_, &pkt);
    if (ret == 0)
    {
        break;
    }
    else if ((ret < 0) && (ret != AVERROR(EAGAIN)))
    {
        return false;
    }
    else if (ret == AVERROR(EAGAIN))
    {
        ret = avcodec_send_frame(av_codec_context_, tmp_picture);
        if (0 > ret)
        {
            return false;
        }
    }
} while (ret == 0);

// the do while is called 46 times, then i get the packet, but i want to get the packet at the first call

It would be very nice if you can help me.

Thanks guys.

like image 877
MrEinsa Avatar asked May 29 '26 07:05

MrEinsa


1 Answers

I assume you just want to encode a single frame. You need to flush the encoder after you have sent your single uncompressed frame by sending NULL instead of a valid buffer.

int result = 0;

// encoder init


// send one uncompressed frame
result = avcodec_send_frame(av_codec_context_, tmp_picture);

if (result < 0) return false;

// send NULL to indicate flushing
result = avcodec_send_frame(av_codec_context_, NULL);


if (result < 0) return false;


while (result != AVERROR_EOF)
{
    result = avcodec_receive_packet(av_codec_context_, &pkt);

    if (!result)
    {
        // you should have your encoded frame; do something with it
    }
}
like image 200
Markus Schumann Avatar answered May 31 '26 21:05

Markus Schumann



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!