Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@

**<span style="color:#56adda">0.1.18</span>**
- adds similar logic for qsv and vaapi as was done for nvenc in 0.1.17
- adds new qsv_safe_decode and vaapi_safe_decode options to the respective encoders
- adds new paths in their respective define_filtergraph functions to move the frames off the GPU to avoid h/w accel failure due to midstream colorspace changes
- adds '-reinit_filter 0' option to the ffmpeg command line when the x_safe_option is enabled so that ffmpeg can ignore the filter change that would have resulted from the colorspace change
- the combination of these allows ffmpeg to successfully process the file rather than failing

**<span style="color:#56adda">0.1.17</span>**
- adds nvenc_safe_decode option to allow plugin to avoid an error caused by colorspace changes in the file
- adds new path in the define_filtergraph function to move the frames off the GPU to avoid h/w accel failure due to midstream colorspace changes
Expand Down
2 changes: 1 addition & 1 deletion info.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"on_worker_process": 1
},
"tags": "video,ffmpeg",
"version": "0.1.17"
"version": "0.1.18"
}
30 changes: 28 additions & 2 deletions lib/encoders/qsv.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def provides(self):
def options(self):
return {
"qsv_decoding_method": "cpu",
"qsv_safe_decode": False,
"qsv_preset": "slow",
"qsv_encoder_ratecontrol_method": "LA_ICQ",
"qsv_constant_quantizer_scale": "25",
Expand All @@ -176,6 +177,10 @@ def generate_default_args(self):
"-hwaccel": "qsv",
"-hwaccel_output_format": "qsv",
})

if self.settings.get_setting('qsv_safe_decode'):
generic_kwargs["-reinit_filter"] = "0"

return generic_kwargs, advanced_kwargs

def generate_filtergraphs(self, current_filter_args, smart_filters, encoder_name):
Expand Down Expand Up @@ -238,13 +243,22 @@ def generate_filtergraphs(self, current_filter_args, smart_filters, encoder_name
# Upload to hw frames at the end of the filter
end_chain = start_chain + ["hwupload=extra_hw_frames=64", "format=qsv", f"vpp_qsv=format={target_fmt}"]
end_filter_args.append(",".join(end_chain))
elif self.settings.get_setting('qsv_safe_decode'):
# HW decode + safe mode: force SW frames to avoid hwaccel reconfigure
generic_kwargs['-hwaccel_output_format'] = target_fmt
start_chain = [f"format={target_fmt}"]
if enc_supports_hdr and target_color_config.get('apply_color_params'):
start_chain.append(target_color_config['setparams_filter'])
start_filter_args.append(",".join(start_chain))
end_chain = start_chain + ["hwupload=extra_hw_frames=64", "format=qsv", f"vpp_qsv=format={target_fmt}"]
end_filter_args.append(",".join(end_chain))
else:
# Add hwupload filter that can handle when the frame was decoded in software or hardware
# Pure HW path - frames stay in QSV memory
chain = [f"format={target_fmt}|qsv",
"hwupload=extra_hw_frames=64",
"format=qsv", f"vpp_qsv=format={target_fmt}"]
end_filter_args.append(",".join(chain))

# Add the smart filters to the end
end_filter_args += hw_smart_filters

Expand Down Expand Up @@ -415,6 +429,18 @@ def get_qsv_decoding_method_form_settings(self):
values["display"] = "hidden"
return values

def get_qsv_safe_decode_form_settings(self):
values = {
"label": "Safe decode mode",
"description": "Forces CPU-side frame handling to prevent failures on files with "
"inconsistent color space metadata (common in WEBDL sources).\n"
"Slightly slower due to GPU->CPU->GPU round-trip per frame.",
"sub_setting": True,
}
if self.settings.get_setting('mode') not in ['standard'] or self.settings.get_setting('qsv_decoding_method') != "qsv":
values["display"] = "hidden"
return values

def get_qsv_preset_form_settings(self):
values = {
"label": "Encoder quality preset",
Expand Down
30 changes: 28 additions & 2 deletions lib/encoders/vaapi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

Expand Down Expand Up @@ -89,6 +90,7 @@ def options(self):
return {
"vaapi_device": "none",
"vaapi_decoding_method": "cpu",
"vaapi_safe_decode": False,
"vaapi_encoder_ratecontrol_method": "ICQ",
"vaapi_constant_quantizer_scale": "25",
"vaapi_constant_quality_scale": "23",
Expand Down Expand Up @@ -141,6 +143,9 @@ def generate_default_args(self):
}
advanced_kwargs = {}

if self.settings.get_setting('vaapi_safe_decode'):
generic_kwargs["-reinit_filter"] = "0"

return generic_kwargs, advanced_kwargs

def generate_filtergraphs(self, current_filter_args, smart_filters, encoder_name):
Expand Down Expand Up @@ -203,11 +208,20 @@ def generate_filtergraphs(self, current_filter_args, smart_filters, encoder_name
# Upload to hw frames at the end of the filter
end_chain = start_chain + ["hwupload"]
end_filter_args.append(",".join(end_chain))
elif self.settings.get_setting('vaapi_safe_decode'):
# HW decode + safe mode: force SW frames to avoid hwaccel reconfigure
generic_kwargs['-hwaccel_output_format'] = target_fmt
start_chain = [f"format={target_fmt}"]
if enc_supports_hdr and target_color_config.get('apply_color_params'):
start_chain.append(target_color_config['setparams_filter'])
start_filter_args.append(",".join(start_chain))
end_chain = start_chain + ["hwupload"]
end_filter_args.append(",".join(end_chain))
else:
# Add hwupload filter that can handle when the frame was decoded in software or hardware
# Pure HW path - frames stay in VAAPI memory
chain = [f"format={target_fmt}|vaapi", "hwupload"]
end_filter_args.append(",".join(chain))

# Add the smart filters to the end
end_filter_args += hw_smart_filters

Expand Down Expand Up @@ -382,6 +396,18 @@ def get_vaapi_decoding_method_form_settings(self):
values["display"] = "hidden"
return values

def get_vaapi_safe_decode_form_settings(self):
values = {
"label": "Safe decode mode",
"description": "Forces CPU-side frame handling to prevent failures on files with "
"inconsistent color space metadata (common in WEBDL sources).\n"
"Slightly slower due to GPU->CPU->GPU round-trip per frame.",
"sub_setting": True,
}
if self.settings.get_setting('mode') not in ['standard'] or self.settings.get_setting('vaapi_decoding_method') != "vaapi":
values["display"] = "hidden"
return values

def get_vaapi_encoder_ratecontrol_method_form_settings(self):
values = {
"label": "Encoder ratecontrol method",
Expand Down