diff --git a/README.md b/README.md
index c9df5b0f..20efc8f2 100644
--- a/README.md
+++ b/README.md
@@ -81,8 +81,6 @@ Swap all faces on the `d:\videos\not_a_porn.mp4` video file to the face from `d:
python sin.py --source="d:\pictures\any_picture.jpg" --target="d:\pictures\pngs_dir" --output="d:\pictures\pngs_dir\enhanced" --frame-processor=FaceEnhancer --many-faces --max-memory=24 --execution-provider=cuda --execution-threads=8
```
Enhance all faces in every PNG file in the `d:\pictures\pngs_dir` directory using the `cuda` provider and 8 simultaneous execution threads, with limit of 24 Gb RAM, and save every enhanced image to the `d:\pictures\pngs_dir\enhanced` directory.
-**Note 1**: only PNG images are supported at the moment.
-**Note 2**: even if the selected frame processor does not require a `source`, you should provide one at this time.
## Configuration file
@@ -104,12 +102,24 @@ You also can pass path to the custom configuration file as a command line parame
python sin.py --ini="d:\path\custom.ini"
```
+## How to handle output videos quality/encoding speed/etc?
+
+In brief, sinner relies on the `ffmpeg` software almost every time video processing is required, and it's possible to utilize all the incredible powers of `ffmpeg`. Use the `--ffmpeg_resulting_parameters` key to control how `ffmpeg` will encode the output video: simply pass the usual `ffmpeg` parameters as the value for this key (remember not to forget enclosing the value string in commas). There are some examples:
+
+* `--ffmpeg_resulting_parameters="-c:v libx264 -preset medium -crf 20 -pix_fmt yuv420p"`: use software x264 encoder (`-c:v libx264`) with the medium quality (`-preset medium` and `-crf 20`) and `yuv420p` pixel format. This is the default parameter value.
+* `--ffmpeg_resulting_parameters="-c:v h264_nvenc -preset slow -qp 20 -pix_fmt yuv420p"`: use nVidia GPU-accelerated x264 encoder (`-c:v h264_nvenc`) with the good encoding quality (`-preset slow` and `-qp 20`). This encoder is worth to use if it supported by your GPU.
+* `--ffmpeg_resulting_parameters="-c:v hevc_nvenc -preset slow -qp 20 -pix_fmt yuv420p"`: the same as above, but with x265 encoding.
+* `--ffmpeg_resulting_parameters="-c:v h264_amf -b:v 2M -pix_fmt yuv420p"`: the AMD hardware-accelerated x264 encoder (`-c:v h264_amf`) with 2mbps resulting video bitrate (-b:v 2M). This should be good for AMD GPUs.
+
+And so on. As you can find, there are a lot of different presets and options for the every `ffmpeg` encoder, and you can rely on the [documentation](https://ffmpeg.org/ffmpeg-codecs.html) to achieve desired results.
+
+In case, when `ffmpeg` is not available in your system, sinner will gracefully degrade to CV2 library possibilities. In that case all video processing features should work, but in a very basic way: only with the software x264 encoder, which is slow and thriftless.
+
## FAQ
:question: What are the differences between sinner and roop?
:exclamation: As said before, sinner has started as a fork of roop. They share similar ideas, but they differ in the ways how those ideas should be implemented.
-sinner uses the same ML libraries to perform its magic, but handles them in its own way. From a developer's perspective, it has a better architecture (OOP instead of functional approach),
- stricter types handling and more comprehensive tests. From the point of view of a user, sinner offers additional features that Roop currently lacks.
+sinner uses the same ML libraries to perform its magic, but handles them in its own way. From a developer's perspective, it has a better architecture (OOP instead of functional approach), stricter types handling and more comprehensive tests. From the point of view of a user, sinner offers additional features that Roop currently lacks.
:question: Is there a NSWF filter?
:exclamation: Nope. I don't care if you will do nasty things with sinner, it's your responsibility. And sinner is just a neutral tool, like a hammer or a knife, it is the responsibility of the user to decide how they want to use it.
diff --git a/sinner/handlers/frame/FFmpegVideoHandler.py b/sinner/handlers/frame/FFmpegVideoHandler.py
index a98d4a1a..0648c97c 100644
--- a/sinner/handlers/frame/FFmpegVideoHandler.py
+++ b/sinner/handlers/frame/FFmpegVideoHandler.py
@@ -18,6 +18,7 @@ class FFmpegVideoHandler(BaseFrameHandler):
emoji: str = '🎥'
output_fps: float
+ ffmpeg_resulting_parameters: str
def rules(self) -> Rules:
return super().rules() + [
@@ -26,6 +27,11 @@ def rules(self) -> Rules:
'default': lambda: self.fps,
'help': 'FPS of resulting video'
},
+ {
+ 'parameter': ['ffmpeg_resulting_parameters'],
+ 'default': '-c:v libx264 -preset medium -crf 20 -pix_fmt yuv420p',
+ 'help': 'ffmpeg command-line part to adjust resulting video parameters'
+ },
{
'module_help': 'The video processing module, based on ffmpeg'
}
@@ -97,8 +103,9 @@ def result(self, from_dir: str, filename: str, audio_target: str | None = None)
self.update_status(f"Resulting frames from {from_dir} to {filename} with {self.output_fps} FPS")
filename_length = len(str(self.fc)) # a way to determine frame names length
Path(os.path.dirname(filename)).mkdir(parents=True, exist_ok=True)
- command = ['-r', str(self.output_fps), '-i', os.path.join(from_dir, f'%0{filename_length}d.png'), '-c:v', 'h264_nvenc', '-preset', 'medium', '-qp', '18', '-pix_fmt', 'yuv420p', '-vf',
- 'colorspace=bt709:iall=bt601-6-625:fast=1', filename]
+ command = ['-framerate', str(self.output_fps), '-i', os.path.join(from_dir, f'%0{filename_length}d.png')]
+ command.extend(self.ffmpeg_resulting_parameters.split(' '))
+ command.extend(['-r', str(self.output_fps), filename])
if audio_target:
command.extend(['-i', audio_target, '-shortest'])
return self.run(command)