[FFmpeg-devel] ffmpeg nvenc

Michael Niedermayer michaelni at gmx.at
Thu Dec 18 12:26:47 CET 2014


On Thu, Dec 18, 2014 at 01:35:05PM +0800, ahu wrote:
[...]
>  configure                    |   11 
>  doc/examples/Makefile        |    1 
>  doc/examples/libnvenc.c      |  198 +++++++++
>  ffmpeg.c                     |    2 
>  libavcodec/Makefile          |    1 
>  libavcodec/allcodecs.c       |    1 
>  libavcodec/libnvenc.c        |  413 ++++++++++++++++++++
>  libavcodec/libnvenc.h        |  142 +++++++
>  libavcodec/nvencoder.c       |  864 +++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/nvencoder.h       |   98 ++++
>  libavcodec/nvencoder_utils.c |  345 +++++++++++++++++
>  libavcodec/nvencoder_utils.h |   30 +
>  libavformat/matroskaenc.c    |    2 
>  libavformat/movenc.c         |    6 
>  14 files changed, 2109 insertions(+), 5 deletions(-)
> 02de15b36b3a5f675e720ebac609d82831ef2d58  0001-add-libnvenc-support.patch
> From 98dbd7bd1894dc438b8fe909373d6ec2f4ddb6f3 Mon Sep 17 00:00:00 2001
> From: agathah <ahu at nvidia.com>
> Date: Thu, 18 Dec 2014 12:01:15 +0800
> Subject: [PATCH] add libnvenc support
> 
> ---
>  configure                    |  11 +
>  doc/examples/Makefile        |   1 +
>  doc/examples/libnvenc.c      | 198 ++++++++++
>  ffmpeg.c                     |   2 +-
>  libavcodec/Makefile          |   1 +
>  libavcodec/allcodecs.c       |   1 +
>  libavcodec/libnvenc.c        | 413 +++++++++++++++++++++
>  libavcodec/libnvenc.h        | 142 +++++++
>  libavcodec/nvencoder.c       | 864 +++++++++++++++++++++++++++++++++++++++++++
>  libavcodec/nvencoder.h       |  98 +++++
>  libavcodec/nvencoder_utils.c | 345 +++++++++++++++++
>  libavcodec/nvencoder_utils.h |  30 ++
>  libavformat/matroskaenc.c    |   2 +-
>  libavformat/movenc.c         |   6 +-
>  14 files changed, 2109 insertions(+), 5 deletions(-)
>  create mode 100644 doc/examples/libnvenc.c
>  create mode 100644 libavcodec/libnvenc.c
>  create mode 100644 libavcodec/libnvenc.h
>  create mode 100644 libavcodec/nvencoder.c
>  create mode 100644 libavcodec/nvencoder.h
>  create mode 100644 libavcodec/nvencoder_utils.c
>  create mode 100644 libavcodec/nvencoder_utils.h
> 
> diff --git a/configure b/configure
> index 3328026..798db4c 100644
> --- a/configure
> +++ b/configure
> @@ -264,6 +264,7 @@ External library support:
>    --disable-lzma           disable lzma [autodetect]
>    --enable-decklink        enable Blackmagick DeckLink I/O support [no]
>    --enable-nvenc           enable NVIDIA NVENC support [no]
> +  --enable-libnvenc		   enable NVIDIA NVENC support [no]

tabs are forbidden in ffmpeg git except makefiles


[...]
> +int main(int argc, char* argv[])
> +{
> +    char* inputfile   = NULL;
> +    char* preset      = "default";
> +    bool  zerolatency = false;
> +

> +    for(int i = 1; i < argc; i++) {

the int i should be outside the for() for slightly improved
compiler compatibility


[...]
> +    enc_ctx->time_base.den = dec_ctx->time_base.den/2;           
> +    enc_ctx->bit_rate	   = bitrate;                
> +    enc_ctx->flags        |= (oc->oformat->flags & AVFMT_GLOBALHEADER) ? CODEC_FLAG_GLOBAL_HEADER : 0;
> +    av_opt_set(enc_ctx->priv_data, "preset", preset, 0);  // "fast" = HP, "slow" = HQ, default = LOW_LATENCY_DEFAULT
> +    if(zerolatency) {
> +        //use LOW_LATENCY preset
> +        av_opt_set(enc_ctx->priv_data, "tune", "zerolatency", 0);
> +    }
> +
> +    ret = avcodec_open2(enc_ctx, enc, NULL);
> +    if (ret < 0) {
> +        printf("could not open codec\n");
> +        return -1;
> +    }
> +    ret = avformat_write_header(oc, NULL);
> +
> +    AVPacket dec_pkt;
> +    av_init_packet(&dec_pkt);

> +    dec_pkt.data = NULL;
> +    dec_pkt.size = 0;
> +
> +    AVFrame *frame = avcodec_alloc_frame();
> +    int got_frame = 0;

mixed declarations and statements


> +    while(av_read_frame(fmt_ctx, &dec_pkt) >= 0) {  
> +        if(dec_pkt.stream_index == video_stream_idx) {
> +            if(avcodec_decode_video2(dec_ctx, frame, &got_frame, &dec_pkt) < 0) {
> +                printf("Error decoding frames!\n");
> +                return -1;
> +            }
> +            if(got_frame) {
> +                AVPacket enc_pkt;
> +                int got_pkt = 0;
> +                av_init_packet(&enc_pkt);
> +                enc_pkt.data = NULL;
> +                enc_pkt.size = 0;       
> +                if(avcodec_encode_video2(vst_enc->codec, &enc_pkt, frame, &got_pkt) < 0) {
> +                    printf("Error encoding frames!\n");
> +                    return -1;
> +                }
> +
> +                if(got_pkt) {
> +                    av_write_frame(oc, &enc_pkt);
> +                }
> +
> +                av_free_packet(&enc_pkt);  
> +            }
> +        }
> +        av_free_packet(&dec_pkt);             
> +    }
> +    avcodec_free_frame(&frame);
> +    av_write_trailer(oc);
> +
> +    avcodec_close(dec_ctx);
> +    avcodec_close(enc_ctx);
> +    avformat_close_input(&fmt_ctx);
> +
> +    return 0;

> +}
> \ No newline at end of file

git says it already


[...]
> +// ffmpeg-x264 param-to-string macros
> +#define OPT_STRSTR(x, y)\
> +    if (y)\
> +    {\
> +        x264_argv[x264_argc++] = av_strdup(x);  \
> +        x264_argv[x264_argc++] = av_strdup(y);  \
> +    }
> +#define OPT_NUMSTR(x, y)\
> +    if (y > 0)\
> +    {\
> +        x264_argv[x264_argc++] = av_strdup(x);               \
> +        x264_argv[x264_argc] = av_malloc(sizeof(char) * 32); \

> +        sprintf(x264_argv[x264_argc++], "%u", y);            \

this probably should be a snprintf() for saftey


[...]
> +    // Enumerate input formats
> +    count = 0, count_ret = 0;
> +    nvenc_status = nvenc->api.nvEncGetInputFormatCount(nvenc->inst, NV_ENC_CODEC_H264_GUID, &count);
> +    if (nvenc_status == NV_ENC_SUCCESS)
> +    {
> +        nvenc->buffer_fmts = (NV_ENC_BUFFER_FORMAT*)malloc(sizeof(NV_ENC_BUFFER_FORMAT)* count);
> +        if (nvenc->buffer_fmts)
> +        {
> +            memset(nvenc->buffer_fmts, 0, sizeof(NV_ENC_BUFFER_FORMAT)* count);

av_mallocz()


> +            nvenc_status = nvenc->api.nvEncGetInputFormats(nvenc->inst, NV_ENC_CODEC_H264_GUID, nvenc->buffer_fmts, count, &count_ret);
> +            if ((nvenc_status != NV_ENC_SUCCESS) || (count_ret == 0))
> +            {
> +                return false;
> +            }
> +            nvenc->num_buffer_fmts = count_ret;
> +        }
> +    }
> +
> +    return true;
> +}
> +

> +static bool open(nvencoder_t *nvenc)
> +{
> +    NVENCSTATUS nvenc_status = NV_ENC_ERR_GENERIC;
> +    nvencodeapicreateinstance_t encodeapicreateinst;
> +    NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS open_encode_session_params;
> +
> +    // Dynamically load NVENC library
> +    nvenc->lib = LoadLibrary(NVENCODEAPI_LIB);
> +    if (!nvenc->lib)
> +    {
> +        return false;
> +    }
> +    encodeapicreateinst =
> +        (nvencodeapicreateinstance_t)GetProcAddress(nvenc->lib, "NvEncodeAPICreateInstance");
> +    if (!encodeapicreateinst)
> +    {
> +        return false;
> +    }
> +
> +    // Initialize function table
> +    nvenc->api.version = NV_ENCODE_API_FUNCTION_LIST_VER;
> +    nvenc_status = encodeapicreateinst(&nvenc->api);
> +    if (nvenc_status != NV_ENC_SUCCESS)
> +    {
> +        return false;
> +    }
> +
> +    if (!init_device(nvenc))
> +    {
> +        return false;
> +    }
> +
> +    // Open encoder session
> +    memset(&open_encode_session_params, 0, sizeof(open_encode_session_params));
> +    open_encode_session_params.version      = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER;
> +    open_encode_session_params.apiVersion   = NVENCAPI_VERSION;
> +    open_encode_session_params.device       = nvenc->device.ptr;
> +    open_encode_session_params.deviceType   = nvenc->device.type;
> +
> +    nvenc_status = nvenc->api.nvEncOpenEncodeSessionEx(&open_encode_session_params, &nvenc->inst);
> +    if (nvenc_status != NV_ENC_SUCCESS)
> +    {
> +        return false;
> +    }
> +
> +    // Find encoder capabilities
> +    if (!query_caps(nvenc))
> +    {
> +        return false;
> +    }
> +
> +    return true;

error codes are AVERROR* in FFmpeg
non errors are >= 0


[...]
> +static void close(nvencoder_t *nvenc)
> +{
> +    if (nvenc->buffer_fmts)
> +    {

> +        free(nvenc->buffer_fmts);
> +        nvenc->buffer_fmts = NULL;

av_freep()


[...]
> +static bool map_x264_to_nvenc(NV_ENC_INITIALIZE_PARAMS *nvenc_init_params, const x264_params_t *x264_params)
> +{
> +    uint32_t qp_ipdiff = (uint32_t)(6 * log2f(x264_params->ipratio > 0.f ? x264_params->ipratio : 1.4f));
> +    uint32_t qp_pbdiff = (uint32_t)(6 * log2f(x264_params->pbratio > 0.f ? x264_params->pbratio : 1.3f));
> +
> +    // Preset
> +    if (x264_params->profile)
> +    {
> +        nvenc_init_params->encodeConfig->profileGUID = map_profile(x264_params->profile);
> +    }
> +    if (x264_params->preset)
> +    {
> +        nvenc_init_params->presetGUID = map_preset(x264_params->preset);
> +    }
> +    if (x264_params->tune)
> +    {
> +        nvenc_init_params->presetGUID = map_tune(x264_params->tune, &nvenc_init_params->presetGUID);
> +    }
> +
> +    // Frame
> +    if ((x264_params->keyint > 0) || (x264_params->min_keyint > 0))
> +    {
> +        if ((x264_params->keyint == 0) || (x264_params->keyint > x264_params->min_keyint))
> +            nvenc_init_params->encodeConfig->gopLength = x264_params->min_keyint;
> +        else
> +            nvenc_init_params->encodeConfig->gopLength = x264_params->keyint;

> +        fprintf(stdout, "%s=%u\n", "gopLength", nvenc_init_params->encodeConfig->gopLength);

av_log()

also see tools/patcheck

[...]
-- 
Michael     GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

Its not that you shouldnt use gotos but rather that you should write
readable code and code with gotos often but not always is less readable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20141218/fe07dad7/attachment.asc>


More information about the ffmpeg-devel mailing list