diff --git a/detect_crop.py b/detect_crop.py deleted file mode 100644 index 9e03ae7..0000000 --- a/detect_crop.py +++ /dev/null @@ -1,79 +0,0 @@ -import subprocess -import re -import sys -import json -from collections import Counter - -def detect_crop(file_path): - cmd = [ - 'ffmpeg', - '-skip_frame', 'nokey', - '-i', file_path, - '-vf', 'cropdetect=limit=24/255:round=16:reset=0', - '-f', 'null', - '-' - ] - - process = subprocess.Popen(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) - crop_pattern = re.compile(r'crop=([0-9]+):([0-9]+):([0-9]+):([0-9]+)') - - crops = [] - - for line in process.stderr: - match = crop_pattern.search(line) - if match: - w, h, x, y = map(int, match.groups()) - # ignorujemy calkowicie ciemne klatki (gdzie cropdetect ucina z kazdej strony) - # interesuje nas glownie format wideo (np proporcje) - crops.append((w, h, x, y)) - - process.wait() - - if not crops: - return {"error": "No crop detected"} - - # Policz jak często występuje dany crop - crop_counts = Counter(crops) - total_frames = len(crops) - - # Filtrujemy losowe błędy i czarne plansze (szukamy cropów które występują co najmniej w 5% klatek kluczowych) - valid_crops = [c for c, count in crop_counts.items() if count / total_frames > 0.05] - - if not valid_crops: - # Jeśli nic nie przekracza 5%, bierzemy po prostu najczęstszy - valid_crops = [crop_counts.most_common(1)[0][0]] - - # Z valid_crops wybieramy taki "safe crop", który jest obwiednią (bounding box) - # dla wszystkich ISTOTNYCH proporcji w filmie. - # To pozwoli na zachowanie scen IMAX, a odcięcie stałych czarnych pasów. - - min_x = min(c[2] for c in valid_crops) - min_y = min(c[3] for c in valid_crops) - max_xw = max(c[2] + c[0] for c in valid_crops) - max_yh = max(c[3] + c[1] for c in valid_crops) - - safe_crop = { - "w": max_xw - min_x, - "h": max_yh - min_y, - "x": min_x, - "y": min_y - } - - most_common_tuple = crop_counts.most_common(1)[0][0] - most_common = f"{most_common_tuple[0]}:{most_common_tuple[1]}:{most_common_tuple[2]}:{most_common_tuple[3]}" - - return { - "safe_crop": safe_crop, - "most_common": most_common, - "valid_crops_considered": len(valid_crops), - "raw_crops_count": total_frames - } - -if __name__ == '__main__': - if len(sys.argv) < 2: - print("Usage: python detect_crop.py ") - sys.exit(1) - - file_path = sys.argv[1] - result = detect_crop(file_path) - print(json.dumps(result, indent=2)) diff --git a/transcode_crop.py b/transcode_crop.py deleted file mode 100644 index 4efe4bf..0000000 --- a/transcode_crop.py +++ /dev/null @@ -1,57 +0,0 @@ -import subprocess -import sys -import os - -def transcode_video(input_file, output_file, crop_param, hw_accel=False): - """ - Transcodes the video and applies cropping. - crop_param: string in the format "W:H:X:Y" - hw_accel: boolean, if true we use hardware acceleration (NVENC as an example) - """ - cmd = ['ffmpeg', '-y', '-i', input_file] - - # We apply the crop filter - vf_param = f'crop={crop_param}' - - if hw_accel: - # Example using NVIDIA NVENC. - # In a real Jellyfin environment, this would be constructed based on Jellyfin's profile. - cmd.extend([ - '-c:v', 'h264_nvenc', - '-preset', 'fast', - '-vf', vf_param, - '-c:a', 'copy' # Keep audio as is - ]) - else: - # Software encoding fallback - cmd.extend([ - '-c:v', 'libx264', - '-preset', 'fast', - '-crf', '23', - '-vf', vf_param, - '-c:a', 'copy' - ]) - - cmd.append(output_file) - - print(f"Running transcoding command: {' '.join(cmd)}") - - # In a real scenario, this would stream to Jellyfin's output or write to the required segment files. - process = subprocess.Popen(cmd) - process.wait() - - if process.returncode == 0: - print("Transcoding completed successfully.") - else: - print(f"Transcoding failed with code {process.returncode}") - -if __name__ == '__main__': - if len(sys.argv) < 4: - print("Usage: python transcode_crop.py ") - sys.exit(1) - - input_file = sys.argv[1] - output_file = sys.argv[2] - crop_param = sys.argv[3] - - transcode_video(input_file, output_file, crop_param, hw_accel=False)