stashapp / stash

An organizer for your porn, written in Go. Documentation: https://docs.stashapp.cc
https://stashapp.cc/
GNU Affero General Public License v3.0
8.71k stars 775 forks source link

[Bug Report] Intel QuickSync not working #5069

Closed gitgiggety closed 2 days ago

gitgiggety commented 1 month ago

Describe the bug For me Intel QuickSync support is not working on an Intel N5105 based system. QSV is tested for / used with a combination of options which is not compatible with at least Jasper Lake CPUs. This is due to -global_quality being used which leads to a ratecontrol as described here: https://ffmpeg.org/ffmpeg-codecs.html#Ratecontrol-Method This while Jasper Lake CPUs are limited in functionality and seemingly only supports some of those ratecontrol methods.

To Reproduce Steps to reproduce the behavior:

  1. Install Stash on a system with a Jasper Lake CPU like an N5105
  2. Enable "FFmpeg hardware encoding"
  3. Restart

Expected behavior Startup log message shows that h264_qsv is supported. But instead is just:

[InitHWSupport] Supported HW codecs [2]: h264_vaapi vp9_vaapi

While this could/should include h264_qsv and possibly vp9_qsv.

Screenshots

Stash Version: (from Settings -> About): 0.26.2

Desktop (please complete the following information):

Smartphone (please complete the following information):

Additional context Trace logs of startup:

[InitHWSupport] Codec h264_qsv not supported. Error output:[h264_qsv @ 0x7fecc212dc00] Error initializing the encoder: invalid video parameters (-15) [vost#0:0/h264_qsv @ 0x7fecc2ac7540] Error while opening encoder - maybe incorrect parameters such as bit_rate, rate, width or height. Error while filtering: Invalid argument [out#0/null @ 0x7fecc2ae5280] Nothing was written into output file, because at least one of its streams received no packets.

Used ffmpeg flags to check QSV support:

-hide_banner -v warning -init_hw_device qsv=hw -filter_hw_device hw -f lavfi -i color=c=red:s=1280x720 -t 0.1 -c:v h264_qsv -global_quality 20 -preset faster -vf hwupload=extra_hw_frames=64,format=qsv,scale_qsv=-1:256 -f null -

Execting ffmpeg with the same flags, except dropping global_quality 20 executes succesfully.

Note: I haven't tested if there are any other issues yet, but transcoding a 4K video to 1280x720 with a basic command like:

ffmpeg -hwaccel qsv -c:v h264_qsv -i input.mp4 -vf scale_qsv=w=1280:h=720 -c:v h264_qsv output.mp4

Does show a speed of ~1.75x, and the CPU not being stressed and intel_gpu_top showing that the GPU is fully used (100% "busy" in the "video" engine). While without qsv the CPU maxes all cores at 100% and the speed is below 1 (so playback actually having to wait for the next pieces to be finished). (But I didn't finish a file and play it back, but I presume it should be working just fine, albeit maybe in a bit lower quality than what it would be if those ratecontrol methods were supported).

gitgiggety commented 1 month ago

I have created a small Python script which I configured as FFmpeg path in Stash. This script takes the original arguments but removes the -global_quality option from it. And with this video transcoding does work fine using QSV hardware transcoding.

This is the script:

#!/usr/bin/python

import os
import sys

args=["/usr/bin/ffmpeg"]
i=1
while i < len(sys.argv):
    if sys.argv[i] == "-global_quality":
        i += 2
    else:
        args.append(sys.argv[i])
        i += 1

os.execv(args[0], args)
gitgiggety commented 1 month ago

The above actually yields a terrible result / quality. This (probably) as no quality is defined. Using -q instead of -global_quality fixes this. So the wrapper then becomes:

#!/usr/bin/python

import os
import sys

args=["/usr/bin/ffmpeg"]
i=1
while i < len(sys.argv):
    if sys.argv[i] == "-global_quality":
        args.append("-q")
        i += 1
    else:
        args.append(sys.argv[i])
        i += 1

os.execv(args[0], args)

Setting a bitrate using -b:v and/or -maxrate can also be done, but will most likely depend on the chosen resolution etc. I.e.: both set to 5M was fine when testing on 1280x720 and looks to equal -q 20, but will probably be (to) low for 1920x1080 or 4K.

And when testing with a 4K video downscaled to 1280x720 the results of both -q 20 and -b:v 5M -maxrate 5M are of a better quality than software encoding (while without these the quality is way worse than software encoding).

NodudeWasTaken commented 1 month ago

Using -q or -qscale is constant quantization which is generally a bad idea for encoding and we shouldn't default to it (even if we use it on vaapi for the lack of a better option). We should however introduce more customization for each encoder.

gitgiggety commented 1 month ago

@NodudeWasTaken yeah sure. My intention wasn't to push for changing -global_quality to -q. I don't know enough (or actually nothing at all) about this stuff and what the consequences would be of such a change (in performance, quality, needed bitrate / bandwidth, ...).

So just reporting the issue, combined with a command which at least does work, and a work-a-round for others which have the same issue.

Regarding "introduce more customization for each encoder", I'm not sure if that would be the right path. I can imagine that would become hugely complex and overwelming, while there already are settings to add "input" and "output" flags to ffmpeg commands which users already can use to fine tune the transcoding. And in this specific case it ideally should "just work". Possibly by expanding the implemented encoders with a new one for this scenario. So run a test with QSV + -global_quality and a test with QSV + -q. Which will result in either both or only the last succeeding / being possible. And I assume there is already a "priority" implemented for all supported encoders which in this case should prioratize the -global_quality one.

Net005 commented 1 week ago

@gitgiggety Tried the Python wrapper as ffmpeg path however it keeps reporting file not found even though it's there:

vivaldi_PdOVAdWtMm

If I add a binary file original ffmpeg as ffmpeg_qsv for testing at same location it works without errors. Any pointers on how to get this working?

Stash version: v0.26.2-63-ga94bf29b Running in latest docker container