FFMPEG H264对每个图像进行编码

时间:2018-03-23 09:31:28

标签: c++ ffmpeg encode h.264

我目前编码从RGB888到H264的QImage,但我想自己编码每个图像(即使这不是完美的方式)。 我能够对图像进行编码,但需要将相同的图像发送46次。我不知道我做错了什么(可能错误的编码配置,但我找不到问题)。

然后我解码此图像,然后将其转换回QImage。我这样做只是为了测试其他一些代码。

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

如果你能帮助我,那将是非常好的。

谢谢你们。

1 个答案:

答案 0 :(得分:2)

我假设你只想编码一个帧。在通过发送NULL而不是有效缓冲区发送单个未压缩帧之后,需要刷新编码器。

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
    }
}