Esempio n. 1
0
static int nvenc_check_codec_support(AVCodecContext *avctx)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    int i, ret, count = 0;
    GUID *guids = NULL;

    ret = nv->nvEncGetEncodeGUIDCount(ctx->nvenc_ctx, &count);

    if (ret != NV_ENC_SUCCESS || !count)
        return AVERROR(ENOSYS);

    guids = av_malloc(count * sizeof(GUID));
    if (!guids)
        return AVERROR(ENOMEM);

    ret = nv->nvEncGetEncodeGUIDs(ctx->nvenc_ctx, guids, count, &count);
    if (ret != NV_ENC_SUCCESS) {
        ret = AVERROR(ENOSYS);
        goto fail;
    }

    ret = AVERROR(ENOSYS);
    for (i = 0; i < count; i++) {
        if (!memcmp(&guids[i], &ctx->params.encodeGUID, sizeof(*guids))) {
            ret = 0;
            break;
        }
    }

fail:
    av_free(guids);

    return ret;
}
Esempio n. 2
0
av_cold int ff_nvenc_encode_close(AVCodecContext *avctx)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    int i;

    if (ctx->in) {
        for (i = 0; i < ctx->nb_surfaces; ++i) {
            nv->nvEncDestroyInputBuffer(ctx->nvenc_ctx, ctx->in[i].in);
            nv->nvEncDestroyBitstreamBuffer(ctx->nvenc_ctx, ctx->out[i].out);
        }
    }

    av_freep(&ctx->in);
    av_freep(&ctx->out);

    if (ctx->nvenc_ctx)
        nv->nvEncDestroyEncoder(ctx->nvenc_ctx);

    if (ctx->cu_context)
        ctx->nvel.cu_ctx_destroy(ctx->cu_context);

    if (ctx->nvel.nvenc)
        dlclose(ctx->nvel.nvenc);

    if (ctx->nvel.cuda)
        dlclose(ctx->nvel.cuda);

    return 0;
}
Esempio n. 3
0
static int nvenc_get_frame(AVCodecContext *avctx, AVPacket *pkt)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    NV_ENC_LOCK_BITSTREAM params    = { 0 };
    NVENCOutputSurface *out         = NULL;
    int ret;

    ret = nvenc_dequeue_surface(ctx->pending, &out);
    if (ret)
        return ret;

    params.version         = NV_ENC_LOCK_BITSTREAM_VER;
    params.outputBitstream = out->out;

    ret = nv->nvEncLockBitstream(ctx->nvenc_ctx, &params);
    if (ret < 0)
        return AVERROR_UNKNOWN;

    ret = ff_alloc_packet(pkt, params.bitstreamSizeInBytes);
    if (ret < 0)
        return ret;

    memcpy(pkt->data, params.bitstreamBufferPtr, pkt->size);

    ret = nv->nvEncUnlockBitstream(ctx->nvenc_ctx, out->out);
    if (ret < 0)
        return AVERROR_UNKNOWN;

    out->busy = out->in->locked = 0;

    ret = nvenc_set_timestamp(ctx, &params, pkt);
    if (ret < 0)
        return ret;

    switch (params.pictureType) {
    case NV_ENC_PIC_TYPE_IDR:
        pkt->flags |= AV_PKT_FLAG_KEY;
#if FF_API_CODED_FRAME
FF_DISABLE_DEPRECATION_WARNINGS
    case NV_ENC_PIC_TYPE_INTRA_REFRESH:
    case NV_ENC_PIC_TYPE_I:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
        break;
    case NV_ENC_PIC_TYPE_P:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P;
        break;
    case NV_ENC_PIC_TYPE_B:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B;
        break;
    case NV_ENC_PIC_TYPE_BI:
        avctx->coded_frame->pict_type = AV_PICTURE_TYPE_BI;
        break;
FF_ENABLE_DEPRECATION_WARNINGS
#endif
    }

    return 0;
}
bool fcH264EncoderNVIDIA::encode(fcH264Frame& dst, const void *image, fcPixelFormat fmt, fcTime timestamp, bool force_keyframe)
{
    if (!isValid()) { return false; }

    dst.timestamp = timestamp;

    // convert image to NV12
    AnyToNV12(m_nv12_image, m_rgba_image, image, fmt, m_conf.width, m_conf.height);
    NV12Data data = m_nv12_image.data();

    NVENCSTATUS stat;

    // upload image to input buffer
    {
        NV_ENC_LOCK_INPUT_BUFFER lock_params = { 0 };
        lock_params.version = NV_ENC_LOCK_INPUT_BUFFER_VER;
        lock_params.inputBuffer = m_input.inputBuffer;
        stat = nvenc.nvEncLockInputBuffer(m_encoder, &lock_params);
        memcpy(lock_params.bufferDataPtr, data.y, m_nv12_image.size());
        stat = nvenc.nvEncUnlockInputBuffer(m_encoder, m_input.inputBuffer);
    }


    NV_ENC_PIC_PARAMS params = { 0 };
    params.version = NV_ENC_PIC_PARAMS_VER;
    params.inputBuffer = m_input.inputBuffer;
    params.outputBitstream = m_output.bitstreamBuffer;
    params.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
    params.inputWidth = m_conf.width;
    params.inputHeight = m_conf.height;
    params.completionEvent = 0;
    params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
    params.encodePicFlags = 0;
    if (force_keyframe) {
        params.encodePicFlags |= NV_ENC_PIC_FLAG_FORCEINTRA;
    }
    params.inputTimeStamp = to_usec(timestamp);
    params.inputDuration = to_usec(1.0 / m_conf.target_framerate);

    // encode! 
    stat = nvenc.nvEncEncodePicture(m_encoder, &params);

    // retrieve encoded data
    {
        NV_ENC_LOCK_BITSTREAM lock_params = { 0 };
        lock_params.version = NV_ENC_LOCK_BITSTREAM_VER;
        lock_params.outputBitstream = m_output.bitstreamBuffer;

        stat = nvenc.nvEncLockBitstream(m_encoder, &lock_params);

        dst.data.append((char*)lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes);
        dst.gatherNALInformation();

        stat = nvenc.nvEncUnlockBitstream(m_encoder, m_output.bitstreamBuffer);
    }

    return true;
}
Esempio n. 5
0
static int nvenc_alloc_surface(AVCodecContext *avctx, int idx)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    int ret;
    NV_ENC_CREATE_INPUT_BUFFER in_buffer      = { 0 };
    NV_ENC_CREATE_BITSTREAM_BUFFER out_buffer = { 0 };

    in_buffer.version  = NV_ENC_CREATE_INPUT_BUFFER_VER;
    out_buffer.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;

    in_buffer.width  = avctx->width;
    in_buffer.height = avctx->height;

    in_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;

    switch (avctx->pix_fmt) {
    case AV_PIX_FMT_YUV420P:
        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YV12_PL;
        break;
    case AV_PIX_FMT_NV12:
        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12_PL;
        break;
    case AV_PIX_FMT_YUV444P:
        in_buffer.bufferFmt = NV_ENC_BUFFER_FORMAT_YUV444_PL;
        break;
    default:
        return AVERROR_BUG;
    }

    ret = nv->nvEncCreateInputBuffer(ctx->nvenc_ctx, &in_buffer);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "CreateInputBuffer failed\n");
        return AVERROR_UNKNOWN;
    }

    ctx->in[idx].in        = in_buffer.inputBuffer;
    ctx->in[idx].format    = in_buffer.bufferFmt;

    /* 1MB is large enough to hold most output frames.
     * NVENC increases this automaticaly if it's not enough. */
    out_buffer.size = BITSTREAM_BUFFER_SIZE;

    out_buffer.memoryHeap = NV_ENC_MEMORY_HEAP_SYSMEM_UNCACHED;

    ret = nv->nvEncCreateBitstreamBuffer(ctx->nvenc_ctx, &out_buffer);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "CreateBitstreamBuffer failed\n");
        return AVERROR_UNKNOWN;
    }

    ctx->out[idx].out  = out_buffer.bitstreamBuffer;
    ctx->out[idx].busy = 0;

    return 0;
}
fcH264EncoderNVIDIA::~fcH264EncoderNVIDIA()
{
    if (m_encoder) {
        if (m_input.inputBuffer) {
            nvenc.nvEncDestroyInputBuffer(m_encoder, m_input.inputBuffer);
        }
        if (m_output.bitstreamBuffer) {
            nvenc.nvEncDestroyBitstreamBuffer(m_encoder, m_output.bitstreamBuffer);
        }
        nvenc.nvEncDestroyEncoder(m_encoder);
    }
}
Esempio n. 7
0
static int nvenc_check_cap(AVCodecContext *avctx, NV_ENC_CAPS cap)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    NV_ENC_CAPS_PARAM params        = { 0 };
    int ret, val = 0;

    params.version     = NV_ENC_CAPS_PARAM_VER;
    params.capsToQuery = cap;

    ret = nv->nvEncGetEncodeCaps(ctx->nvenc_ctx, ctx->params.encodeGUID, &params, &val);

    if (ret == NV_ENC_SUCCESS)
        return val;
    return 0;
}
Esempio n. 8
0
static int nvenc_enqueue_frame(AVCodecContext *avctx, const AVFrame *frame,
                               NVENCInputSurface **in_surf)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    NV_ENC_LOCK_INPUT_BUFFER params = { 0 };
    NVENCInputSurface *in           = get_input_surface(ctx);
    int ret;

    if (!in)
        return AVERROR_BUG;

    params.version     = NV_ENC_LOCK_INPUT_BUFFER_VER;
    params.inputBuffer = in->in;


    ret = nv->nvEncLockInputBuffer(ctx->nvenc_ctx, &params);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "Cannot lock the buffer %p.\n",
               in);
        return AVERROR_UNKNOWN;
    }

    ret = nvenc_copy_frame(&params, frame);
    if (ret < 0)
        goto fail;

    ret = nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "Cannot unlock the buffer %p.\n",
               in);
        return AVERROR_UNKNOWN;
    }

    *in_surf = in;

    return 0;

fail:
    nv->nvEncUnlockInputBuffer(ctx->nvenc_ctx, in->in);

    return ret;
}
Esempio n. 9
0
static int nvenc_open_session(AVCodecContext *avctx)
{
    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0 };
    NVENCContext *ctx                           = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv             = &ctx->nvel.nvenc_funcs;
    int ret;

    params.version    = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
    params.apiVersion = NVENCAPI_VERSION;
    params.device     = ctx->cu_context;
    params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;

    ret = nv->nvEncOpenEncodeSessionEx(&params, &ctx->nvenc_ctx);
    if (ret != NV_ENC_SUCCESS) {
        ctx->nvenc_ctx = NULL;
        av_log(avctx, AV_LOG_ERROR,
               "Cannot open the NVENC Session\n");
        return AVERROR_UNKNOWN;
    }

    return 0;
}
Esempio n. 10
0
static int nvenc_setup_extradata(AVCodecContext *avctx)
{
    NVENCContext *ctx                     = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv       = &ctx->nvel.nvenc_funcs;
    NV_ENC_SEQUENCE_PARAM_PAYLOAD payload = { 0 };
    int ret;

    avctx->extradata = av_mallocz(EXTRADATA_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
    if (!avctx->extradata)
        return AVERROR(ENOMEM);

    payload.version              = NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER;
    payload.spsppsBuffer         = avctx->extradata;
    payload.inBufferSize         = EXTRADATA_SIZE;
    payload.outSPSPPSPayloadSize = &avctx->extradata_size;

    ret = nv->nvEncGetSequenceParams(ctx->nvenc_ctx, &payload);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "Cannot get the extradata\n");
        return AVERROR_UNKNOWN;
    }

    return 0;
}
fcH264EncoderNVIDIA::fcH264EncoderNVIDIA(const fcH264EncoderConfig& conf, void *device, fcHWEncoderDeviceType type)
    : m_conf(conf)
{
    if (!LoadNVENCModule()) { return; }

    NVENCSTATUS stat;
    {
        NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params;
        memset(&params, 0, sizeof(params));
        params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
        params.apiVersion = NVENCAPI_VERSION;
        params.device = device;
        switch (type) {
        case fcHWEncoderDeviceType::D3D9:
        case fcHWEncoderDeviceType::D3D10:
        case fcHWEncoderDeviceType::D3D11:
        case fcHWEncoderDeviceType::D3D12:
            params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX;
            break;
        case fcHWEncoderDeviceType::CUDA:
            params.deviceType = NV_ENC_DEVICE_TYPE_CUDA;
            break;
        }
        stat = nvenc.nvEncOpenEncodeSessionEx(&params, &m_encoder);
        if (!m_encoder) {
            return;
        }
    }

    std::vector<GUID> encode_guilds;
    std::vector<GUID> profile_guilds;
    std::vector<GUID> preset_guilds;
    {
        uint32_t num_encode_guilds = 0;
        uint32_t num_profile_guilds = 0;
        uint32_t num_preset_guilds = 0;

        nvenc.nvEncGetEncodeGUIDCount(m_encoder, &num_encode_guilds);
        encode_guilds.resize(num_encode_guilds);
        nvenc.nvEncGetEncodeGUIDs(m_encoder, encode_guilds.data(), num_encode_guilds, &num_encode_guilds);

        nvenc.nvEncGetEncodeProfileGUIDCount(m_encoder, NV_ENC_CODEC_H264_GUID, &num_profile_guilds);
        profile_guilds.resize(num_profile_guilds);
        nvenc.nvEncGetEncodeProfileGUIDs(m_encoder, NV_ENC_CODEC_H264_GUID, profile_guilds.data(), num_profile_guilds, &num_profile_guilds);

        nvenc.nvEncGetEncodePresetCount(m_encoder, NV_ENC_CODEC_H264_GUID, &num_preset_guilds);
        preset_guilds.resize(num_preset_guilds);
        nvenc.nvEncGetEncodePresetGUIDs(m_encoder, NV_ENC_CODEC_H264_GUID, preset_guilds.data(), num_preset_guilds, &num_preset_guilds);
    }

    {
        NV_ENC_INITIALIZE_PARAMS params = { 0 };
        params.version = NV_ENC_INITIALIZE_PARAMS_VER;
        params.encodeGUID = NV_ENC_CODEC_H264_GUID;
        params.presetGUID = NV_ENC_PRESET_DEFAULT_GUID;
        params.encodeWidth = conf.width;
        params.encodeHeight = conf.height;
        params.darWidth = conf.width;
        params.darHeight = conf.height;
        params.frameRateNum = m_conf.target_framerate;
        params.frameRateDen = 1;
        params.enablePTD = 1;

        NV_ENC_PRESET_CONFIG preset_config = { 0 };
        preset_config.version = NV_ENC_PRESET_CONFIG_VER;
        preset_config.presetCfg.version = NV_ENC_CONFIG_VER;
        stat = nvenc.nvEncGetEncodePresetConfig(m_encoder, params.encodeGUID, params.presetGUID, &preset_config);

        NV_ENC_CONFIG encode_config = { 0 };
        encode_config.version = NV_ENC_CONFIG_VER;
        memcpy(&encode_config, &preset_config.presetCfg, sizeof(NV_ENC_CONFIG));
        encode_config.profileGUID = NV_ENC_H264_PROFILE_HIGH_GUID;
        params.encodeConfig = &encode_config;

        stat = nvenc.nvEncInitializeEncoder(m_encoder, &params);
    }

    {
        memset(&m_input, 0, sizeof(m_input));
        m_input.version = NV_ENC_CREATE_INPUT_BUFFER_VER;
        m_input.width = m_conf.width;
        m_input.height = m_conf.height;
        m_input.bufferFmt = NV_ENC_BUFFER_FORMAT_NV12;
        stat = nvenc.nvEncCreateInputBuffer(m_encoder, &m_input);
    }

    {
        memset(&m_output, 0, sizeof(m_output));
        m_output.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER;
        m_output.size = roundup<16>(conf.width) * roundup<16>(conf.height) * 2;
        stat = nvenc.nvEncCreateBitstreamBuffer(m_encoder, &m_output);
    }
}
Esempio n. 12
0
static int nvenc_setup_encoder(AVCodecContext *avctx)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    NV_ENC_PRESET_CONFIG preset_cfg = { 0 };
    int ret;

    ctx->params.version = NV_ENC_INITIALIZE_PARAMS_VER;

    ctx->params.encodeHeight = avctx->height;
    ctx->params.encodeWidth  = avctx->width;

    if (avctx->sample_aspect_ratio.num &&
        avctx->sample_aspect_ratio.den &&
        (avctx->sample_aspect_ratio.num != 1 ||
         avctx->sample_aspect_ratio.den != 1)) {
        av_reduce(&ctx->params.darWidth,
                  &ctx->params.darHeight,
                  avctx->width * avctx->sample_aspect_ratio.num,
                  avctx->height * avctx->sample_aspect_ratio.den,
                  INT_MAX / 8);
    } else {
        ctx->params.darHeight = avctx->height;
        ctx->params.darWidth  = avctx->width;
    }

    ctx->params.frameRateNum = avctx->time_base.den;
    ctx->params.frameRateDen = avctx->time_base.num * avctx->ticks_per_frame;

    ctx->params.enableEncodeAsync = 0;
    ctx->params.enablePTD         = 1;

    ctx->params.encodeConfig = &ctx->config;

    nvec_map_preset(ctx);

    preset_cfg.version           = NV_ENC_PRESET_CONFIG_VER;
    preset_cfg.presetCfg.version = NV_ENC_CONFIG_VER;

    ret = nv->nvEncGetEncodePresetConfig(ctx->nvenc_ctx,
                                         ctx->params.encodeGUID,
                                         ctx->params.presetGUID,
                                         &preset_cfg);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR,
               "Cannot get the preset configuration\n");
        return AVERROR_UNKNOWN;
    }

    memcpy(&ctx->config, &preset_cfg.presetCfg, sizeof(ctx->config));

    ctx->config.version = NV_ENC_CONFIG_VER;

    if (avctx->gop_size > 0) {
        if (avctx->max_b_frames > 0) {
            ctx->last_dts = -2;
            /* 0 is intra-only,
             * 1 is I/P only,
             * 2 is one B Frame,
             * 3 two B frames, and so on. */
            ctx->config.frameIntervalP = avctx->max_b_frames + 1;
        } else if (avctx->max_b_frames == 0) {
            ctx->config.frameIntervalP = 1;
        }
        ctx->config.gopLength = avctx->gop_size;
    } else if (avctx->gop_size == 0) {
        ctx->config.frameIntervalP = 0;
        ctx->config.gopLength      = 1;
    }

    if (ctx->config.frameIntervalP > 1)
        avctx->max_b_frames = ctx->config.frameIntervalP - 1;

    nvenc_setup_rate_control(avctx);

    if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD;
    } else {
        ctx->config.frameFieldMode = NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME;
    }

    if ((ret = nvenc_setup_codec_config(avctx)) < 0)
        return ret;

    ret = nv->nvEncInitializeEncoder(ctx->nvenc_ctx, &ctx->params);
    if (ret != NV_ENC_SUCCESS) {
        av_log(avctx, AV_LOG_ERROR, "Cannot initialize the decoder");
        return AVERROR_UNKNOWN;
    }

    return 0;
}
Esempio n. 13
0
int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                          const AVFrame *frame, int *got_packet)
{
    NVENCContext *ctx               = avctx->priv_data;
    NV_ENCODE_API_FUNCTION_LIST *nv = &ctx->nvel.nvenc_funcs;
    NV_ENC_PIC_PARAMS params        = { 0 };
    NVENCInputSurface *in           = NULL;
    NVENCOutputSurface *out         = NULL;
    int ret;

    params.version = NV_ENC_PIC_PARAMS_VER;

    if (frame) {
        ret = nvenc_enqueue_frame(avctx, frame, &in);
        if (ret < 0)
            return ret;
        out = get_output_surface(ctx);
        if (!out)
            return AVERROR_BUG;

        out->in = in;

        params.inputBuffer     = in->in;
        params.bufferFmt       = in->format;
        params.inputWidth      = frame->width;
        params.inputHeight     = frame->height;
        params.outputBitstream = out->out;
        params.inputTimeStamp  = frame->pts;

        if (avctx->flags & CODEC_FLAG_INTERLACED_DCT) {
            if (frame->top_field_first)
                params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM;
            else
                params.pictureStruct = NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP;
        } else {
            params.pictureStruct = NV_ENC_PIC_STRUCT_FRAME;
        }

        nvenc_codec_specific_pic_params(avctx, &params);

        ret = nvenc_enqueue_timestamp(ctx->timestamps, frame->pts);
        if (ret < 0)
            return ret;
    } else {
        params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
    }

    ret = nv->nvEncEncodePicture(ctx->nvenc_ctx, &params);

    if (ret != NV_ENC_SUCCESS &&
        ret != NV_ENC_ERR_NEED_MORE_INPUT) {

        return AVERROR_UNKNOWN;
    }

    if (out) {
        ret = nvenc_enqueue_surface(ctx->pending, out);
        if (ret < 0)
            return ret;
    }

    if (ret != NV_ENC_ERR_NEED_MORE_INPUT &&
        av_fifo_size(ctx->pending)) {
        ret = nvenc_get_frame(avctx, pkt);
        if (ret < 0)
            return ret;
        *got_packet = 1;
    } else {
        *got_packet = 0;
    }

    return 0;
}