-
Just move
/usr/lib/jellyfin-ffmpeg/ffmpeg
to/usr/lib/jellyfin-ffmpeg/ffmpeg.orig
, and create/usr/lib/jellyfin-ffmpeg/ffmpeg
with the code, and don't forgetsudo chmod +x /usr/lib/jellyfin-ffmpeg/ffmpeg
-
if your cpu is not as strong as 13900h, or you want to support multiple users, you can lower height_preset_*.
-
require
mediainfo
Last active
September 30, 2024 20:15
-
-
Save Saren-Arterius/a1f6d7563a20467981e2fe212955b9de to your computer and use it in GitHub Desktop.
/usr/lib/jellyfin-ffmpeg/ffmpeg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import subprocess | |
import re | |
import json | |
import math | |
height_preset_480 = 5 | |
height_preset_720 = 5 | |
height_preset_1080 = 7 | |
def get_original_resolution(file_path): | |
try: | |
result = subprocess.run(['mediainfo', '--Output=JSON', file_path], | |
capture_output=True, text=True, check=True) | |
info = json.loads(result.stdout) | |
video_track = next(track for track in info['media']['track'] if track['@type'] == 'Video') | |
return int(video_track['Width']), int(video_track['Height']) | |
except Exception as e: | |
print(f"Error getting video information: {e}", file=sys.stderr) | |
return None, None | |
def modify_arguments(args): | |
new_args = [] | |
scale_vaapi_index = None | |
scale_index = None | |
new_width = None | |
new_height = None | |
new_preset = None | |
input_file = None | |
# First pass to find input file, scale_vaapi, and filter_complex | |
for i, arg in enumerate(args): | |
if arg == '-i': | |
input_file = args[i+1].split(':', 1)[-1] # Remove 'file:' prefix if present | |
elif 'scale_vaapi=' in arg: | |
scale_vaapi_index = i | |
elif 'scale=' in arg: | |
scale_index = i | |
if not input_file: | |
print("Error: Input file not found in arguments", file=sys.stderr) | |
return args | |
original_width, original_height = get_original_resolution(input_file) | |
if not original_height: | |
return args # Return original args if we couldn't get the video info | |
# Determine new height and preset | |
match = None | |
if scale_vaapi_index is not None: | |
match = re.search(r'scale_vaapi=w=(\d+):h=(\d+)', args[scale_vaapi_index]) | |
if scale_index is not None: | |
match = re.search(r'scale=(.+):(.+),', args[scale_index]) | |
if match: | |
try: | |
requested_width = int(match.group(1)) | |
requested_height = int(match.group(2)) | |
except Exception as e: | |
requested_width = 480 | |
requested_height = 272 | |
if requested_height <= 480 and original_height >= 720: | |
new_height = 720 | |
new_preset = height_preset_720 | |
elif requested_height <= 240 and original_height >= 480: | |
new_height = 480 | |
new_preset = height_preset_480 | |
else: | |
new_height = min(requested_height, original_height) | |
if new_height <= 480: | |
new_preset = height_preset_480 | |
elif new_height <= 720: | |
new_preset = height_preset_720 | |
elif new_height <= 1080: | |
new_preset = height_preset_1080 | |
if new_height: | |
new_width = math.ceil(original_width * (new_height / original_height) / 4) * 4 | |
else: | |
if original_height <= 480: | |
new_preset = height_preset_480 | |
elif original_height <= 720: | |
new_preset = height_preset_720 | |
elif original_height <= 1080: | |
new_preset = height_preset_1080 | |
# Second pass to modify arguments | |
skip = False | |
for i, arg in enumerate(args): | |
if skip: | |
skip = False | |
continue | |
if i == scale_index and new_width and new_height: | |
scale = arg | |
scale = re.sub(r'scale=(.+):(.+),', f'scale=-2:{new_height},', scale) | |
new_args.append(scale) | |
elif i == scale_vaapi_index and new_width and new_height: | |
filter_complex = arg | |
filter_complex = re.sub(r'scale=-1:(\d+):', f'scale=-1:{new_height}:', filter_complex) | |
filter_complex = re.sub(r'pad=max\((\d+)\\,', f'pad=max({new_width}\\,', filter_complex) | |
# Update pad height | |
filter_complex = re.sub(r':max\((\d+)\\,', f':max({new_height}\\,', filter_complex) | |
# Update crop dimensions | |
filter_complex = re.sub(r'crop=(\d+):(\d+)', f'crop={new_width}:{new_height}', filter_complex) | |
# Update scale_vaapi dimensions | |
filter_complex = re.sub(r'scale_vaapi=w=(\d+):h=(\d+)', f'scale_vaapi=w={new_width}:h={new_height}', filter_complex) | |
new_args.append(filter_complex) | |
elif arg == '-preset': | |
if new_preset: | |
new_args.append(arg) | |
new_args.append(str(new_preset)) | |
else: | |
new_args.append(arg) | |
new_args.append(args[i+1]) | |
skip = True # Skip the next argument as we've handled it | |
else: | |
new_args.append(arg) | |
return new_args | |
def main(): | |
# The path to the real ffmpeg executable | |
real_ffmpeg = "/usr/lib/jellyfin-ffmpeg/ffmpeg.orig" | |
# Get all command line arguments except the script name | |
args = sys.argv[1:] | |
# Modify the arguments | |
modified_args = modify_arguments(args) | |
# Construct the new command | |
command = [real_ffmpeg] + modified_args | |
# Execute the modified ffmpeg command | |
try: | |
result = subprocess.run(command, check=True) | |
except subprocess.CalledProcessError as e: | |
print(f"Error executing ffmpeg: {e}", file=sys.stderr) | |
sys.exit(e.returncode) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment