From be3dded625788399ef672f210a1d11b9b4660549 Mon Sep 17 00:00:00 2001 From: "Josh.5" Date: Sat, 30 Dec 2023 01:53:01 +1300 Subject: [PATCH] Consolidate all information about what encoders and codecs are available in the encoder libs This means to add a new encoder, we only need to add the details in the required lib file which makes it more manageable. --- lib/encoders/libx.py | 17 +++++-- lib/encoders/nvenc.py | 21 ++++++-- lib/encoders/qsv.py | 17 +++++-- lib/encoders/vaapi.py | 17 +++++-- lib/global_settings.py | 95 +++++++++++-------------------------- lib/plugin_stream_mapper.py | 26 +++++----- plugin.py | 23 +++++---- 7 files changed, 111 insertions(+), 105 deletions(-) diff --git a/lib/encoders/libx.py b/lib/encoders/libx.py index bd784e2..ef6c548 100644 --- a/lib/encoders/libx.py +++ b/lib/encoders/libx.py @@ -24,10 +24,16 @@ class LibxEncoder: - encoders = [ - "libx264", - "libx265", - ] + provides = { + "libx264": { + "codec": "h264", + "label": "CPU - libx264", + }, + "libx265": { + "codec": "hevc", + "label": "CPU - libx265", + } + } def __init__(self, settings): self.settings = settings @@ -66,6 +72,9 @@ def generate_filtergraphs(): """ return [] + def encoder_details(self, encoder): + return self.provides.get(encoder, {}) + def args(self, stream_id): stream_encoding = [] diff --git a/lib/encoders/nvenc.py b/lib/encoders/nvenc.py index cbef8f6..cd14725 100644 --- a/lib/encoders/nvenc.py +++ b/lib/encoders/nvenc.py @@ -89,10 +89,16 @@ def get_configured_device(settings): class NvencEncoder: - encoders = [ - "h264_nvenc", - "hevc_nvenc", - ] + provides = { + "h264_nvenc": { + "codec": "h264", + "label": "NVENC - h264_nvenc", + }, + "hevc_nvenc": { + "codec": "hevc", + "label": "NVENC - hevc_nvenc", + } + } def __init__(self, settings): self.settings = settings @@ -155,6 +161,13 @@ def generate_filtergraphs(software_filters, hw_smart_filters): filters.append('scale_cuda={}:-1'.format(scale_values[0])) return filters + def encoder_details(self, encoder): + hardware_devices = list_available_cuda_devices() + if not hardware_devices: + # Return no options. No hardware device was found + return {} + return self.provides.get(encoder, {}) + def args(self, stream_info, stream_id): generic_kwargs = {} stream_encoding = [] diff --git a/lib/encoders/qsv.py b/lib/encoders/qsv.py index 4205d27..9154285 100644 --- a/lib/encoders/qsv.py +++ b/lib/encoders/qsv.py @@ -33,10 +33,16 @@ class QsvEncoder: - encoders = [ - "h264_qsv", - "hevc_qsv", - ] + provides = { + "h264_qsv": { + "codec": "h264", + "label": "QSV - h264_qsv", + }, + "hevc_qsv": { + "codec": "hevc", + "label": "QSV - hevc_qsv", + } + } def __init__(self, settings): self.settings = settings @@ -106,6 +112,9 @@ def generate_filtergraphs(settings, software_filters, hw_smart_filters): filter_args.append('scale_qsv=w={}:h={}'.format(scale_values[0], scale_values[1])) return generic_kwargs, advanced_kwargs, filter_args + def encoder_details(self, encoder): + return self.provides.get(encoder, {}) + def args(self, stream_id): stream_encoding = [] diff --git a/lib/encoders/vaapi.py b/lib/encoders/vaapi.py index 62da8b1..01d3679 100644 --- a/lib/encoders/vaapi.py +++ b/lib/encoders/vaapi.py @@ -47,10 +47,16 @@ def list_available_vaapi_devices(): class VaapiEncoder: - encoders = [ - "h264_vaapi", - "hevc_vaapi", - ] + provides = { + "h264_vaapi": { + "codec": "h264", + "label": "VAAPI - h264_vaapi", + }, + "hevc_vaapi": { + "codec": "hevc", + "label": "VAAPI - hevc_vaapi", + } + } def __init__(self, settings): self.settings = settings @@ -126,6 +132,9 @@ def generate_filtergraphs(): """ return ["format=nv12|vaapi,hwupload"] + def encoder_details(self, encoder): + return self.provides.get(encoder, {}) + def args(self, stream_id): stream_encoding = [] diff --git a/lib/global_settings.py b/lib/global_settings.py index c199ca7..eb32906 100644 --- a/lib/global_settings.py +++ b/lib/global_settings.py @@ -21,12 +21,19 @@ If not, see . """ -import os import subprocess -import sys from video_transcoder.lib import tools +supported_codecs = { + "h264": { + "label": "H264" + }, + "hevc": { + "label": "HEVC/H265" + }, +} + class GlobalSettings: @@ -143,17 +150,15 @@ def get_video_codec_form_settings(self): "label": "Video Codec", "description": "Select the video codec that your video library should be.", "input_type": "select", - "select_options": [ - { - "value": "h264", - "label": "H264", - }, - { - "value": "hevc", - "label": "HEVC/H265", - }, - ], + "select_options": [], } + for key in supported_codecs: + values['select_options'].append( + { + "value": key, + "label": supported_codecs.get(key, {}).get('label'), + } + ) self.__set_default_option(values['select_options'], 'video_codec') if self.settings.get_setting('mode') not in ['basic', 'standard', 'advanced']: values["display"] = 'hidden' @@ -177,63 +182,19 @@ def get_video_encoder_form_settings(self): values = { "label": "Video Encoder", "input_type": "select", - "select_options": [ - { - "value": "libx264", - "label": "CPU - libx264", - }, - ], + "select_options": [], } - if self.settings.get_setting('video_codec') == 'h264': - values['select_options'] = [ - { - "value": "libx264", - "label": "CPU - libx264", - }, + for encoder_name in self.settings.encoders: + encoder_lib = self.settings.encoders.get(encoder_name) + encoder_details = encoder_lib.encoder_details(encoder_name) + if encoder_details.get('codec') != self.settings.get_setting('video_codec'): + continue + values['select_options'].append( { - "value": "h264_qsv", - "label": "QSV - h264_qsv", - }, - ] - if os.name == 'posix' and sys.platform == 'linux': - values['select_options'] += [ - { - "value": "h264_vaapi", - "label": "VAAPI - h264_vaapi", - }, - ] - if self.__is_nvidia_gpu_present(): - values['select_options'] += [ - { - "value": "h264_nvenc", - "label": "NVENC - h264_nvenc", - }, - ] - elif self.settings.get_setting('video_codec') == 'hevc': - values['select_options'] = [ - { - "value": "libx265", - "label": "CPU - libx265", - }, - { - "value": "hevc_qsv", - "label": "QSV - hevc_qsv", - }, - ] - if os.name == 'posix' and sys.platform == 'linux': - values['select_options'] += [ - { - "value": "hevc_vaapi", - "label": "VAAPI - hevc_vaapi", - }, - ] - if self.__is_nvidia_gpu_present(): - values['select_options'] += [ - { - "value": "hevc_nvenc", - "label": "NVENC - hevc_nvenc", - }, - ] + "value": encoder_name, + "label": encoder_details.get('label'), + } + ) self.__set_default_option(values['select_options'], 'video_encoder') if self.settings.get_setting('mode') not in ['basic', 'standard']: values["display"] = 'hidden' diff --git a/lib/plugin_stream_mapper.py b/lib/plugin_stream_mapper.py index e1a0dea..97481fa 100644 --- a/lib/plugin_stream_mapper.py +++ b/lib/plugin_stream_mapper.py @@ -92,19 +92,19 @@ def set_default_values(self, settings, abspath, probe): # Build hardware acceleration args based on encoder # Note: these are not applied to advanced mode - advanced mode was returned above - if self.settings.get_setting('video_encoder') in LibxEncoder.encoders: + if self.settings.get_setting('video_encoder') in LibxEncoder.provides: generic_kwargs, advanced_kwargs = LibxEncoder.generate_default_args(self.settings) self.set_ffmpeg_generic_options(**generic_kwargs) self.set_ffmpeg_advanced_options(**advanced_kwargs) - elif self.settings.get_setting('video_encoder') in QsvEncoder.encoders: + elif self.settings.get_setting('video_encoder') in QsvEncoder.provides: generic_kwargs, advanced_kwargs = QsvEncoder.generate_default_args(self.settings) self.set_ffmpeg_generic_options(**generic_kwargs) self.set_ffmpeg_advanced_options(**advanced_kwargs) - elif self.settings.get_setting('video_encoder') in VaapiEncoder.encoders: + elif self.settings.get_setting('video_encoder') in VaapiEncoder.provides: generic_kwargs, advanced_kwargs = VaapiEncoder.generate_default_args(self.settings) self.set_ffmpeg_generic_options(**generic_kwargs) self.set_ffmpeg_advanced_options(**advanced_kwargs) - elif self.settings.get_setting('video_encoder') in NvencEncoder.encoders: + elif self.settings.get_setting('video_encoder') in NvencEncoder.provides: generic_kwargs, advanced_kwargs = NvencEncoder.generate_default_args(self.settings) self.set_ffmpeg_generic_options(**generic_kwargs) self.set_ffmpeg_advanced_options(**advanced_kwargs) @@ -166,9 +166,9 @@ def build_filter_chain(self, stream_info, stream_id): vid_width, vid_height = self.scale_resolution(stream_info) if vid_width: # Apply scale with only width to keep aspect ratio - if self.settings.get_setting('video_encoder') in QsvEncoder.encoders: + if self.settings.get_setting('video_encoder') in QsvEncoder.provides: required_hw_smart_filters.append({'scale': [vid_width, vid_height]}) - elif self.settings.get_setting('video_encoder') in NvencEncoder.encoders: + elif self.settings.get_setting('video_encoder') in NvencEncoder.provides: required_hw_smart_filters.append({'scale': [vid_width, vid_height]}) else: software_filters.append('scale={}:-1'.format(vid_width)) @@ -180,21 +180,21 @@ def build_filter_chain(self, stream_info, stream_id): software_filters.append(software_filter.strip()) # Check for hardware encoders that required video filters - if self.settings.get_setting('video_encoder') in QsvEncoder.encoders: + if self.settings.get_setting('video_encoder') in QsvEncoder.provides: # Add filtergraph required for using QSV encoding generic_kwargs, advanced_kwargs, filter_args = QsvEncoder.generate_filtergraphs(self.settings, software_filters, required_hw_smart_filters) self.set_ffmpeg_generic_options(**generic_kwargs) self.set_ffmpeg_advanced_options(**advanced_kwargs) hardware_filters += filter_args - elif self.settings.get_setting('video_encoder') in VaapiEncoder.encoders: + elif self.settings.get_setting('video_encoder') in VaapiEncoder.provides: # Add filtergraph required for using VAAPI encoding hardware_filters += VaapiEncoder.generate_filtergraphs() # If we are using software filters, then disable vaapi surfaces. # Instead, output software frames if software_filters: self.set_ffmpeg_generic_options(**{'-hwaccel_output_format': 'nv12'}) - elif self.settings.get_setting('video_encoder') in NvencEncoder.encoders: + elif self.settings.get_setting('video_encoder') in NvencEncoder.provides: # Add filtergraph required for using CUDA encoding hardware_filters += NvencEncoder.generate_filtergraphs(software_filters, required_hw_smart_filters) # If we are using software filters, then disable cuda surfaces. @@ -320,16 +320,16 @@ def custom_stream_mapping(self, stream_info: dict, stream_id: int): ] # Add encoder args - if self.settings.get_setting('video_encoder') in LibxEncoder.encoders: + if self.settings.get_setting('video_encoder') in LibxEncoder.provides: qsv_encoder = LibxEncoder(self.settings) stream_encoding += qsv_encoder.args(stream_id) - elif self.settings.get_setting('video_encoder') in QsvEncoder.encoders: + elif self.settings.get_setting('video_encoder') in QsvEncoder.provides: qsv_encoder = QsvEncoder(self.settings) stream_encoding += qsv_encoder.args(stream_id) - elif self.settings.get_setting('video_encoder') in VaapiEncoder.encoders: + elif self.settings.get_setting('video_encoder') in VaapiEncoder.provides: vaapi_encoder = VaapiEncoder(self.settings) stream_encoding += vaapi_encoder.args(stream_id) - elif self.settings.get_setting('video_encoder') in NvencEncoder.encoders: + elif self.settings.get_setting('video_encoder') in NvencEncoder.provides: nvenc_encoder = NvencEncoder(self.settings) generic_kwargs, stream_encoding_args = nvenc_encoder.args(stream_info, stream_id) self.set_ffmpeg_generic_options(**generic_kwargs) diff --git a/plugin.py b/plugin.py index 41e8497..32f1a9e 100644 --- a/plugin.py +++ b/plugin.py @@ -54,15 +54,7 @@ class Settings(PluginSettings): def __init__(self, *args, **kwargs): super(Settings, self).__init__(*args, **kwargs) self.settings = self.__build_settings_object() - self.encoders = { - "libx265": LibxEncoder(self), - "libx264": LibxEncoder(self), - "hevc_qsv": QsvEncoder(self), - "h264_qsv": QsvEncoder(self), - "hevc_vaapi": VaapiEncoder(self), - "h264_vaapi": VaapiEncoder(self), - "h264_nvenc": NvencEncoder(self), - } + self.encoders = self.__available_encoders() self.global_settings = GlobalSettings(self) self.form_settings = self.__build_form_settings_object() @@ -96,6 +88,19 @@ def __build_form_settings_object(self): return_values[setting] = setting_form_settings return return_values + def __available_encoders(self): + return_encoders = {} + encoder_libs = [ + LibxEncoder, + QsvEncoder, + VaapiEncoder, + NvencEncoder, + ] + for encoder_lib in encoder_libs: + for encoder in encoder_lib.provides: + return_encoders[encoder] = encoder_lib(self) + return return_encoders + def __encoder_settings_object(self): """ Returns a list of encoder settings for FFmpeg