From: Jaroslav Kysela Date: Mon, 4 Sep 2017 14:49:43 +0000 (+0200) Subject: transcode: added h264_nvenc and hevc_nvenc codecs (untested) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6c45b859a706e064b196ef4c761d28afcdff06e6;p=thirdparty%2Ftvheadend.git transcode: added h264_nvenc and hevc_nvenc codecs (untested) --- diff --git a/Makefile b/Makefile index b8f0f6944..531f5e265 100644 --- a/Makefile +++ b/Makefile @@ -499,6 +499,9 @@ endif ifeq ($(CONFIG_VAAPI),yes) LIBS-CODECS += vaapi endif +ifeq ($(CONFIG_NVENC),yes) +LIBS-CODECS += nvenc +endif ifeq ($(CONFIG_OMX),yes) LIBS-CODECS += omx endif diff --git a/Makefile.ffmpeg b/Makefile.ffmpeg index 450014d5e..8ae182966 100644 --- a/Makefile.ffmpeg +++ b/Makefile.ffmpeg @@ -542,7 +542,7 @@ endif ifeq (yes,$(CONFIG_NVENC)) EXTLIBS += nvenc -ENCODERS += nvenc_h264 nvenc_hevc +ENCODERS += h264_nvenc hevc_nvenc endif diff --git a/configure b/configure index 231df2347..8cd4d588b 100755 --- a/configure +++ b/configure @@ -534,10 +534,12 @@ if enabled ffmpeg_static; then fi # nvenc - if enabled nvenc; then - check_cc_header nvEncodeAPI || \ - die "NVENC library (https://developer.nvidia.com/nvidia-video-codec-sdk) not found" - fi + # latest ffmpeg has own code + enable nvenc + #if enabled nvenc; then + # check_cc_header nvEncodeAPI || \ + # die "NVENC library (https://developer.nvidia.com/nvidia-video-codec-sdk) not found" + #fi # omx if enabled omx; then diff --git a/src/transcoding/codec/codec.c b/src/transcoding/codec/codec.c index bcf58c424..eee2956e1 100644 --- a/src/transcoding/codec/codec.c +++ b/src/transcoding/codec/codec.c @@ -64,6 +64,11 @@ extern TVHCodec tvh_codec_vaapi_hevc; extern TVHCodec tvh_codec_vaapi_vp8; #endif +#if ENABLE_NVENC +extern TVHCodec tvh_codec_nvenc_h264; +extern TVHCodec tvh_codec_nvenc_hevc; +#endif + #if ENABLE_OMX extern TVHCodec tvh_codec_omx_h264; #endif @@ -279,6 +284,11 @@ tvh_codecs_register() tvh_codec_register(&tvh_codec_vaapi_vp8); #endif +#if ENABLE_NVENC + tvh_codec_register(&tvh_codec_nvenc_h264); + tvh_codec_register(&tvh_codec_nvenc_hevc); +#endif + #if ENABLE_OMX tvh_codec_register(&tvh_codec_omx_h264); #endif diff --git a/src/transcoding/codec/codecs/libs/nvenc.c b/src/transcoding/codec/codecs/libs/nvenc.c new file mode 100644 index 000000000..4acbb28c6 --- /dev/null +++ b/src/transcoding/codec/codecs/libs/nvenc.c @@ -0,0 +1,320 @@ +/* + * tvheadend - Codec Profiles + * + * Copyright (C) 2017 Tvheadend + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "transcoding/codec/internals.h" +#include +#include + +#define PRESET_DEFAULT 0 +#define PRESET_SLOW 1 +#define PRESET_MEDIUM 2 +#define PRESET_FAST 3 +#define PRESET_HP 4 +#define PRESET_HQ 5 +#define PRESET_BD 6 +#define PRESET_LOW_LATENCY_DEFAULT 7 +#define PRESET_LOW_LATENCY_HQ 8 +#define PRESET_LOW_LATENCY_HP 9 +#define PRESET_LOSSLESS_DEFAULT 10 +#define PRESET_LOSSLESS_HP 11 + +#define NV_ENC_PARAMS_RC_AUTO 0 +#define NV_ENC_PARAMS_RC_CONSTQP 1 +#define NV_ENC_PARAMS_RC_VBR 2 +#define NV_ENC_PARAMS_RC_CBR 3 +#define NV_ENC_PARAMS_RC_VBR_MINQP 4 +#define NV_ENC_PARAMS_RC_2_PASS_QUALITY 5 +#define NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP 6 +#define NV_ENC_PARAMS_RC_2_PASS_VBR 7 + +#define AV_DICT_SET_CQ(d, v, a) \ + AV_DICT_SET_INT((d), "cq", (v) ? (v) : (a), AV_DICT_DONT_OVERWRITE) + + +/* nvenc ==================================================================== */ + +typedef struct { + TVHVideoCodecProfile; + int nvenc_profile; + int devicenum; + int preset; + int rc; + int quality; +} tvh_codec_profile_nvenc_t; + +static int +tvh_codec_profile_nvenc_open(tvh_codec_profile_nvenc_t *self, + AVDictionary **opts) +{ + static const struct strtab presettab[] = { + {"default", PRESET_DEFAULT}, + {"slow", PRESET_SLOW}, + {"medium", PRESET_MEDIUM}, + {"fast", PRESET_FAST}, + {"hp", PRESET_HP}, + {"hq", PRESET_HQ}, + {"bd", PRESET_BD}, + {"ll", PRESET_LOW_LATENCY_DEFAULT}, + {"llhq", PRESET_LOW_LATENCY_HQ}, + {"llhp", PRESET_LOW_LATENCY_HP}, + {"lossless", PRESET_LOSSLESS_DEFAULT}, + {"losslesshp", PRESET_LOSSLESS_HP}, + }; + static const struct strtab rctab[] = { + {"constqp", NV_ENC_PARAMS_RC_CONSTQP}, + {"vbr", NV_ENC_PARAMS_RC_VBR}, + {"cbr", NV_ENC_PARAMS_RC_CBR}, + {"vbr_minqp", NV_ENC_PARAMS_RC_VBR_MINQP}, + {"ll_2pass_quality", NV_ENC_PARAMS_RC_2_PASS_QUALITY}, + {"ll_2pass_size", NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP}, + {"vbr_2pass", NV_ENC_PARAMS_RC_2_PASS_VBR}, + }; + const char *s; + + AV_DICT_SET_INT(opts, "gpu", MINMAX(self->devicenum, 0, 15), 0); + if (self->preset != PRESET_DEFAULT && + (s = val2str(self->profile, presettab)) != NULL) { + AV_DICT_SET(opts, "preset", s, 0); + } + if (self->rc != NV_ENC_PARAMS_RC_AUTO && + (s = val2str(self->rc, rctab)) != NULL) { + AV_DICT_SET(opts, "rc", s, 0); + } + if (self->bit_rate) { + AV_DICT_SET_BIT_RATE(opts, self->bit_rate); + } + AV_DICT_SET_INT(opts, "quality", self->quality, 0); + return 0; +} + +static htsmsg_t * +codec_profile_nvenc_class_profile_list(void *obj, const char *lang) +{ + TVHCodec *codec = tvh_codec_profile_get_codec(obj); + return tvh_codec_get_list(codec, profiles); +} + +static htsmsg_t * +codec_profile_nvenc_class_preset_list(void *obj, const char *lang) +{ + static const struct strtab tab[] = { + {N_("Default"), PRESET_DEFAULT}, + {N_("Slow"), PRESET_SLOW}, + {N_("Medium"), PRESET_MEDIUM}, + {N_("Fast"), PRESET_FAST}, + {N_("HP"), PRESET_HP}, + {N_("HQ"), PRESET_HQ}, + {N_("BD"), PRESET_BD}, + {N_("Low latency"), PRESET_LOW_LATENCY_DEFAULT}, + {N_("Low latency HQ"), PRESET_LOW_LATENCY_HQ}, + {N_("Low latency HP"), PRESET_LOW_LATENCY_HP}, + {N_("Lossless"), PRESET_LOSSLESS_DEFAULT}, + {N_("Lossless HP"), PRESET_LOSSLESS_HP}, + }; + return strtab2htsmsg(tab, 1, lang); +} + +static htsmsg_t * +codec_profile_nvenc_class_rc_list(void *obj, const char *lang) +{ + static const struct strtab tab[] = { + {N_("Auto"), NV_ENC_PARAMS_RC_AUTO}, + {N_("Constant QP mode"), NV_ENC_PARAMS_RC_CONSTQP}, + {N_("VBR mode"), NV_ENC_PARAMS_RC_VBR}, + {N_("CBR mode"), NV_ENC_PARAMS_RC_CBR}, + {N_("VBR mode with MinQP"), NV_ENC_PARAMS_RC_VBR_MINQP}, + {N_("VBR multi-pass LL quality mode"), NV_ENC_PARAMS_RC_2_PASS_QUALITY}, + {N_("VBR multi-pass LL frame size mode"), NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP}, + {N_("VBR multi-pass mode"), NV_ENC_PARAMS_RC_2_PASS_VBR}, + }; + return strtab2htsmsg(tab, 1, lang); +} + +static const codec_profile_class_t codec_profile_nvenc_class = { + { + .ic_super = (idclass_t *)&codec_profile_video_class, + .ic_class = "codec_profile_nvenc", + .ic_caption = N_("nvenc"), + .ic_properties = (const property_t[]){ + { + .type = PT_INT, + .id = "devicenum", + .name = N_("GPU number"), + .group = 3, + .desc = N_("GPU number (starts with zero)."), + .get_opts = codec_profile_class_get_opts, + .off = offsetof(tvh_codec_profile_nvenc_t, devicenum), + }, + { + .type = PT_INT, + .id = "profile", + .name = N_("Profile"), + .desc = N_("Profile."), + .group = 4, + .opts = PO_ADVANCED | PO_PHIDDEN, + .get_opts = codec_profile_class_profile_get_opts, + .off = offsetof(tvh_codec_profile_nvenc_t, nvenc_profile), + .list = codec_profile_nvenc_class_profile_list, + .def.i = FF_PROFILE_UNKNOWN, + }, + { + .type = PT_INT, + .id = "preset", + .name = N_("Preset"), + .group = 3, + .desc = N_("Override the preset rate control."), + .get_opts = codec_profile_class_get_opts, + .off = offsetof(tvh_codec_profile_nvenc_t, preset), + .list = codec_profile_nvenc_class_preset_list, + .def.i = PRESET_DEFAULT, + }, + { + .type = PT_DBL, + .id = "bit_rate", + .name = N_("Bitrate (kb/s) (0=auto)"), + .desc = N_("Target bitrate."), + .group = 3, + .get_opts = codec_profile_class_get_opts, + .off = offsetof(TVHCodecProfile, bit_rate), + .def.d = 0, + }, + { + .type = PT_INT, + .id = "quality", + .name = N_("Quality (0=auto)"), + .desc = N_("Set encode quality (trades off against speed, " + "higher is faster) [0-51]."), + .group = 5, + .opts = PO_EXPERT, + .get_opts = codec_profile_class_get_opts, + .off = offsetof(tvh_codec_profile_nvenc_t, quality), + .intextra = INTEXTRA_RANGE(0, 51, 1), + .def.i = 0, + }, + { + .type = PT_INT, + .id = "rc", + .name = N_("Rate control"), + .group = 3, + .desc = N_("Override the preset rate control."), + .opts = PO_EXPERT, + .off = offsetof(tvh_codec_profile_nvenc_t, rc), + .list = codec_profile_nvenc_class_rc_list, + .def.i = NV_ENC_PARAMS_RC_AUTO, + }, + {} + } + }, + .open = (codec_profile_open_meth)tvh_codec_profile_nvenc_open, +}; + + +/* h264_nvenc =============================================================== */ + +static const AVProfile nvenc_h264_profiles[] = { + { FF_PROFILE_H264_BASELINE, "Baseline" }, + { FF_PROFILE_H264_MAIN, "Main" }, + { FF_PROFILE_H264_HIGH, "High" }, + { FF_PROFILE_H264_HIGH_444_PREDICTIVE, "High 444P" }, + { FF_PROFILE_UNKNOWN }, +}; + +static int +tvh_codec_profile_nvenc_h264_open(tvh_codec_profile_nvenc_t *self, + AVDictionary **opts) +{ + static const struct strtab profiletab[] = { + {"baseline", FF_PROFILE_H264_BASELINE}, + {"main", FF_PROFILE_H264_MAIN}, + {"high", FF_PROFILE_H264_HIGH,}, + {"high444p", FF_PROFILE_H264_HIGH_444_PREDICTIVE}, + }; + const char *s; + + if (self->nvenc_profile != FF_PROFILE_UNKNOWN && + (s = val2str(self->nvenc_profile, profiletab)) != NULL) + AV_DICT_SET(opts, "profile", s, 0); + return 0; +} + + +static const codec_profile_class_t codec_profile_nvenc_h264_class = { + { + .ic_super = (idclass_t *)&codec_profile_nvenc_class, + .ic_class = "codec_profile_nvenc_h264", + .ic_caption = N_("nvenc_h264"), + .ic_properties = (const property_t[]){ + {} + } + }, + .open = (codec_profile_open_meth)tvh_codec_profile_nvenc_h264_open, +}; + + +TVHVideoCodec tvh_codec_nvenc_h264 = { + .name = "h264_nvenc", + .size = sizeof(tvh_codec_profile_nvenc_t), + .idclass = &codec_profile_nvenc_h264_class, + .profiles = nvenc_h264_profiles, +}; + + +/* hevc_nvenc =============================================================== */ + +static const AVProfile nvenc_hevc_profiles[] = { + { FF_PROFILE_HEVC_MAIN, "Main" }, + { FF_PROFILE_HEVC_MAIN_10, "Main 10" }, + { FF_PROFILE_UNKNOWN }, +}; + +static int +tvh_codec_profile_nvenc_hevc_open(tvh_codec_profile_nvenc_t *self, + AVDictionary **opts) +{ + static const struct strtab profiletab[] = { + {"main", FF_PROFILE_HEVC_MAIN}, + {"main10", FF_PROFILE_HEVC_MAIN_10,}, + }; + const char *s; + + if (self->nvenc_profile != FF_PROFILE_UNKNOWN && + (s = val2str(self->nvenc_profile, profiletab)) != NULL) + AV_DICT_SET(opts, "profile", s, 0); + return 0; +} + + +static const codec_profile_class_t codec_profile_nvenc_hevc_class = { + { + .ic_super = (idclass_t *)&codec_profile_nvenc_class, + .ic_class = "codec_profile_nvenc_hevc", + .ic_caption = N_("nvenc_hevc") + }, + .open = (codec_profile_open_meth)tvh_codec_profile_nvenc_hevc_open, +}; + + +TVHVideoCodec tvh_codec_nvenc_hevc = { + .name = "hevc_nvenc", + .size = sizeof(tvh_codec_profile_nvenc_t), + .idclass = &codec_profile_nvenc_hevc_class, + .profiles = nvenc_hevc_profiles, + .profile_init = tvh_codec_profile_video_init, +};