diff --git a/premiere_to_resolve.py b/premiere_to_resolve.py index 2e751fc..89c3811 100644 --- a/premiere_to_resolve.py +++ b/premiere_to_resolve.py @@ -3,7 +3,9 @@ Premiere to Resolve XML Converter Processes Adobe Premiere Pro XML exports to make them compatible with DaVinci Resolve on Linux. -Updates file paths and optionally converts MP4 files to MOV format. +Updates file paths and optionally converts MP4 files to MOV by re-encoding to Resolve-friendly +codecs (ProRes 422 HQ, DNxHD, or H.264 in MOV). Stream copy is not used so Resolve can read +the resulting files on Linux. """ import os @@ -121,71 +123,105 @@ def find_local_files(video_refs: Set[Tuple[str, str]], directory: str) -> Dict[s def convert_mp4_to_mov(input_file: str, output_file: str) -> bool: """ - Convert MP4 to MOV using ffmpeg with minimal quality loss. - - Strategy: - 1. Try copy codecs first (lossless if compatible) - 2. Fallback to high-quality encoding + Convert MP4 to MOV by re-encoding to a codec DaVinci Resolve on Linux supports. + + Resolve on Linux does not reliably support H.264-in-MP4 or stream-copied + codecs in MOV. We always re-encode to ProRes 422 HQ (decode-only on Linux + but fully supported for import), with fallback to DNxHD or H.264 in MOV. """ # Check if output file already exists if os.path.exists(output_file): response = input(f"Output file {output_file} already exists. Overwrite? (y/n): ") if response.lower() != 'y': return False - - # Try copy codecs first (lossless if compatible) - cmd_copy = [ - 'ffmpeg', '-i', input_file, - '-c:v', 'copy', - '-c:a', 'copy', - '-y', # Overwrite output file - output_file + + try: + subprocess.run(["ffmpeg", "-version"], capture_output=True, timeout=5) + except (FileNotFoundError, subprocess.TimeoutExpired): + print("Error: ffmpeg not found. Please install ffmpeg.", file=sys.stderr) + return False + + # 1. Prefer ProRes 422 HQ – well supported for import in Resolve on Linux + cmd_prores = [ + "ffmpeg", + "-i", + input_file, + "-c:v", + "prores", + "-profile:v", + "2", # ProRes 422 HQ + "-c:a", + "pcm_s16le", # Uncompressed audio, always supported + "-y", + output_file, ] - try: result = subprocess.run( - cmd_copy, - capture_output=True, - text=True, - timeout=3600 # 1 hour timeout + cmd_prores, capture_output=True, text=True, timeout=3600 ) - if result.returncode == 0: - print(f" Converted (copy codecs): {os.path.basename(input_file)} -> {os.path.basename(output_file)}") + print( + f" Converted (ProRes 422 HQ): {os.path.basename(input_file)} -> {os.path.basename(output_file)}" + ) return True except subprocess.TimeoutExpired: print(f" Timeout converting {input_file}", file=sys.stderr) return False - except FileNotFoundError: - print("Error: ffmpeg not found. Please install ffmpeg.", file=sys.stderr) - return False - - # Fallback to high-quality encoding - print(f" Copy codecs not compatible, using high-quality encoding for {os.path.basename(input_file)}") - cmd_encode = [ - 'ffmpeg', '-i', input_file, - '-c:v', 'libx264', - '-crf', '18', # High quality (lower = better quality) - '-preset', 'slow', # Better compression - '-c:a', 'copy', # Copy audio - '-y', - output_file + + # 2. Fallback: DNxHD 120 (1080p-friendly, full encode/decode support on Resolve Linux) + print(f" ProRes failed, trying DNxHD for {os.path.basename(input_file)}") + cmd_dnx = [ + "ffmpeg", + "-i", + input_file, + "-c:v", + "dnxhd", + "-b:v", + "120M", # DNxHD 120 Mbps (1080p) + "-c:a", + "pcm_s16le", + "-y", + output_file, ] - try: - result = subprocess.run( - cmd_encode, - capture_output=True, - text=True, - timeout=3600 - ) - + result = subprocess.run(cmd_dnx, capture_output=True, text=True, timeout=3600) if result.returncode == 0: - print(f" Converted (encoded): {os.path.basename(input_file)} -> {os.path.basename(output_file)}") + print( + f" Converted (DNxHD): {os.path.basename(input_file)} -> {os.path.basename(output_file)}" + ) return True - else: - print(f" Error converting {input_file}: {result.stderr}", file=sys.stderr) - return False + except subprocess.TimeoutExpired: + print(f" Timeout converting {input_file}", file=sys.stderr) + return False + + # 3. Last resort: H.264 in MOV (re-encoded, not copy) + print(f" DNxHD failed, using H.264 in MOV for {os.path.basename(input_file)}") + cmd_h264 = [ + "ffmpeg", + "-i", + input_file, + "-c:v", + "libx264", + "-crf", + "18", + "-preset", + "slow", + "-pix_fmt", + "yuv420p", # Maximum compatibility + "-c:a", + "pcm_s16le", + "-y", + output_file, + ] + try: + result = subprocess.run(cmd_h264, capture_output=True, text=True, timeout=3600) + if result.returncode == 0: + print( + f" Converted (H.264 MOV): {os.path.basename(input_file)} -> {os.path.basename(output_file)}" + ) + return True + print(f" Error converting {input_file}: {result.stderr}", file=sys.stderr) + return False except subprocess.TimeoutExpired: print(f" Timeout converting {input_file}", file=sys.stderr) return False