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))