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. 2
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;
}