Esempio n. 1
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(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);
    }
}