[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