diff --git a/encode_dvr.bat b/encode_dvr.bat deleted file mode 100644 index 663e8ba..0000000 --- a/encode_dvr.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_dvr.py -pause \ No newline at end of file diff --git a/encode_dvr.py b/encode_dvr.py deleted file mode 100644 index 16b37b3..0000000 --- a/encode_dvr.py +++ /dev/null @@ -1,209 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', - '-progress', 'pipe:1', # Force progress output to stdout - '-stats', # Show encoding statistics - '-stats_period', '0.5', # Update stats every 0.5 seconds - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', # Variable bitrate mode - '-rc-lookahead', '32', # Increase lookahead for better VBR decisions - '-spatial-aq', '1', # Enable spatial AQ for better quality - '-aq-strength', '15', # Maximum allowed AQ strength - '-cq', '35', - '-b:v', '0', # Let VBR determine bitrate - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg with timeout - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Set timeout to 5 minutes - timeout = 300 - start_time = datetime.now() - - # Log FFmpeg output in real-time - while True: - # Check for timeout - if (datetime.now() - start_time).total_seconds() > timeout: - process.kill() - raise TimeoutError(f"FFmpeg process timed out after {timeout} seconds") - - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except TimeoutError as e: - logging.error(f"Timeout error: {e}") - print(f"{Colors.RED}Timeout error: {e}{Colors.ENDC}") - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - except Exception as e: - logging.error(f"Unexpected error: {e}") - print(f"{Colors.RED}Unexpected error: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_dvr_23.bat b/encode_dvr_23.bat deleted file mode 100644 index 4652a58..0000000 --- a/encode_dvr_23.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_dvr_23.py -pause \ No newline at end of file diff --git a/encode_dvr_23.py b/encode_dvr_23.py deleted file mode 100644 index e46be1e..0000000 --- a/encode_dvr_23.py +++ /dev/null @@ -1,191 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', # Enable verbose output - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', # Variable bitrate mode - '-rc-lookahead', '32', # Increase lookahead for better VBR decisions - '-spatial-aq', '1', # Enable spatial AQ for better quality - '-aq-strength', '15', # Maximum allowed AQ strength - '-cq', '23', - '-b:v', '0', # Let VBR determine bitrate - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_dvr_lossless.bat b/encode_dvr_lossless.bat deleted file mode 100644 index d41f700..0000000 --- a/encode_dvr_lossless.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_dvr_lossless.py -pause \ No newline at end of file diff --git a/encode_dvr_lossless.py b/encode_dvr_lossless.py deleted file mode 100644 index bd0ed90..0000000 --- a/encode_dvr_lossless.py +++ /dev/null @@ -1,191 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', # Enable verbose output - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', # Variable bitrate mode - '-rc-lookahead', '32', # Increase lookahead for better VBR decisions - '-spatial-aq', '1', # Enable spatial AQ for better quality - '-aq-strength', '15', # Maximum allowed AQ strength - '-cq', '0', - '-b:v', '0', # Let VBR determine bitrate - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_dvr_lossless_maxrate.bat b/encode_dvr_lossless_maxrate.bat deleted file mode 100644 index 3bc758a..0000000 --- a/encode_dvr_lossless_maxrate.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_dvr_lossless_maxrate.py -pause \ No newline at end of file diff --git a/encode_dvr_lossless_maxrate.py b/encode_dvr_lossless_maxrate.py deleted file mode 100644 index 1587279..0000000 --- a/encode_dvr_lossless_maxrate.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', - '-rc-lookahead', '32', - '-spatial-aq', '1', - '-aq-strength', '15', - '-cq', '0', - '-b:v', '0', - '-maxrate', '10000k', - '-bufsize', '20000k', - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_dvr_lossless_vp9.bat b/encode_dvr_lossless_vp9.bat deleted file mode 100644 index 3d920de..0000000 --- a/encode_dvr_lossless_vp9.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_dvr_lossless_vp9.py -pause \ No newline at end of file diff --git a/encode_dvr_lossless_vp9.py b/encode_dvr_lossless_vp9.py deleted file mode 100644 index d628a48..0000000 --- a/encode_dvr_lossless_vp9.py +++ /dev/null @@ -1,191 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command for high-quality VP9 encoding - cmd = [ - 'ffmpeg', - '-v', 'verbose', - '-i', str(input_path), - '-c:v', 'libvpx-vp9', - '-crf', '0', # Extremely high quality (0=lossless, 5-10=extremely high) - '-b:v', '10000k', - '-maxrate', '10000k', - '-cpu-used', '0', # Slowest encoding for highest quality - '-row-mt', '1', - '-threads', '0', - '-tile-columns', '2', # Better quality for 1080p - '-frame-parallel', '1', # Parallel frame processing - '-lag-in-frames', '25', # More frames for better compression - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_vtubrec2500.bat b/encode_vtubrec2500.bat deleted file mode 100644 index ed74b60..0000000 --- a/encode_vtubrec2500.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_vtubrec2500.py -pause \ No newline at end of file diff --git a/encode_vtubrec2500.py b/encode_vtubrec2500.py deleted file mode 100644 index dcbc1ef..0000000 --- a/encode_vtubrec2500.py +++ /dev/null @@ -1,193 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', - '-rc-lookahead', '32', - '-spatial-aq', '1', - '-aq-strength', '15', - '-cq', '26', - '-b:v', '2500k', - '-maxrate', '2500k', - '-bufsize', '5000k', - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/encode_vtubrec5k.bat b/encode_vtubrec5k.bat deleted file mode 100644 index be1d679..0000000 --- a/encode_vtubrec5k.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -python encode_vtubrec5k.py -pause \ No newline at end of file diff --git a/encode_vtubrec5k.py b/encode_vtubrec5k.py deleted file mode 100644 index 31d7ef4..0000000 --- a/encode_vtubrec5k.py +++ /dev/null @@ -1,194 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime -import shutil - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -def get_gpu_selection(): - while True: - print(f"\n{Colors.BLUE}Select GPU slot:{Colors.ENDC}") - print("0 - First GPU") - print("1 - Second GPU") - print("2 - Third GPU") - gpu = input(f"{Colors.YELLOW}Enter GPU number (0-2):{Colors.ENDC} ").strip() - if gpu in ['0', '1', '2']: - return gpu - print(f"{Colors.RED}Invalid selection. Please try again.{Colors.ENDC}") - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"encode_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def get_file_info(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height,r_frame_rate,channels,channel_layout', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - return json.loads(result.stdout) - -def get_audio_labels(input_file): - cmd = [ - 'ffprobe', - '-v', 'error', - '-select_streams', 'a', - '-show_entries', 'stream=index:stream_tags=title', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - info = json.loads(result.stdout) - labels = [] - for stream in info.get('streams', []): - title = stream.get('tags', {}).get('title', None) - labels.append(title) - return labels - -def format_size(size_bytes): - for unit in ['B', 'KB', 'MB', 'GB']: - if size_bytes < 1024: - return f"{size_bytes:.2f} {unit}" - size_bytes /= 1024 - return f"{size_bytes:.2f} TB" - -def encode_dvr(input_file, output_dir, gpu): - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}{input_path.suffix}" - - # Get file info for logging - file_info = get_file_info(str(input_path)) - input_size = int(file_info['format']['size']) - duration = float(file_info['format']['duration']) - - logging.info(f"Processing file: {input_path}") - logging.info(f"Input size: {format_size(input_size)}") - logging.info(f"Duration: {duration:.2f} seconds") - - print(f"\n{Colors.BLUE}Processing file: {input_path}{Colors.ENDC}") - print(f"Input size: {format_size(input_size)}") - print(f"Duration: {duration:.2f} seconds") - - # Log stream information - for i, stream in enumerate(file_info.get('streams', [])): - stream_type = 'Video' if stream.get('codec_name', '').startswith('h') else 'Audio' - logging.info(f"Stream {i} ({stream_type}):") - for key, value in stream.items(): - logging.info(f" {key}: {value}") - - # Skip if output file already exists - if output_path.exists(): - output_size = output_path.stat().st_size - logging.info(f"Skipping {input_path} - output already exists: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - print(f"{Colors.YELLOW}Skipping {input_path} - output already exists{Colors.ENDC}") - return - - # Get audio labels - audio_labels = get_audio_labels(str(input_path)) - logging.info(f"Audio labels: {audio_labels}") - - # FFmpeg command with NVIDIA HEVC encoder and maximum quality - cmd = [ - 'ffmpeg', - '-v', 'verbose', - '-i', str(input_path), - '-c:v', 'hevc_nvenc', - '-gpu', gpu, - '-preset', 'p7', - '-tune', 'hq', - '-rc', 'vbr', - '-rc-lookahead', '32', - '-spatial-aq', '1', - '-aq-strength', '15', - '-cq', '23', - '-b:v', '5000k', - '-maxrate', '5000k', - '-bufsize', '10000k', - '-b:a', '192k', - '-c:a', 'copy', - '-map', '0', - ] - # Add metadata for each audio stream if label exists - for idx, label in enumerate(audio_labels): - if label: - cmd += [f'-metadata:s:a:{idx}', f'title={label}'] - cmd.append(str(output_path)) - - try: - # Run FFmpeg and capture output - process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True - ) - - # Log FFmpeg output in real-time - while True: - output = process.stderr.readline() - if output == '' and process.poll() is not None: - break - if output: - logging.info(f"FFmpeg: {output.strip()}") - print(f"{Colors.PURPLE}FFmpeg: {output.strip()}{Colors.ENDC}") - - if process.returncode == 0: - # Get output file info - output_info = get_file_info(str(output_path)) - output_size = int(output_info['format']['size']) - compression_ratio = input_size / output_size if output_size > 0 else 0 - - logging.info(f"Successfully encoded: {output_path}") - logging.info(f"Output size: {format_size(output_size)}") - logging.info(f"Compression ratio: {compression_ratio:.2f}x") - print(f"{Colors.GREEN}Successfully encoded: {output_path}{Colors.ENDC}") - print(f"Compression ratio: {compression_ratio:.2f}x") - else: - logging.error(f"FFmpeg process failed with return code {process.returncode}") - print(f"{Colors.RED}FFmpeg process failed with return code {process.returncode}{Colors.ENDC}") - - except subprocess.CalledProcessError as e: - logging.error(f"Error encoding {input_path}: {e}") - print(f"{Colors.RED}Error encoding {input_path}: {e}{Colors.ENDC}") - -if __name__ == "__main__": - # Get GPU selection - gpu = get_gpu_selection() - logging.info(f"Selected GPU: {gpu}") - - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of files to process - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - logging.info("No files to process in input directory") - print(f"{Colors.YELLOW}No files to process in input directory{Colors.ENDC}") - else: - logging.info(f"Found {total_files} files to process") - print(f"{Colors.BLUE}Found {total_files} files to process{Colors.ENDC}") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - logging.info(f"Processing file {i}/{total_files}: {file}") - print(f"\n{Colors.BLUE}Processing file {i}/{total_files}: {file}{Colors.ENDC}") - encode_dvr(input_file, output_dir, gpu) \ No newline at end of file diff --git a/repair_mp4.bat b/repair_mp4.bat deleted file mode 100644 index 4de7388..0000000 --- a/repair_mp4.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo off -python repair_mp4.py -pause - - - diff --git a/repair_mp4.py b/repair_mp4.py deleted file mode 100644 index c03e790..0000000 --- a/repair_mp4.py +++ /dev/null @@ -1,239 +0,0 @@ -import os -import subprocess -from pathlib import Path -import json -import logging -from datetime import datetime - -# ANSI color codes -class Colors: - PURPLE = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - YELLOW = '\033[93m' - RED = '\033[91m' - ENDC = '\033[0m' - -# Set up logging -log_dir = "logs" -os.makedirs(log_dir, exist_ok=True) -log_file = os.path.join(log_dir, f"repair_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log") -logging.basicConfig(filename=log_file, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') - -def check_file_health(input_file): - """Check if MP4 file has issues using ffmpeg""" - print(f"\n{Colors.BLUE}Analyzing: {input_file}{Colors.ENDC}") - logging.info(f"Analyzing file: {input_file}") - - cmd = [ - 'ffmpeg', - '-v', 'error', - '-i', str(input_file), - '-f', 'null', - '-' - ] - - result = subprocess.run(cmd, capture_output=True, text=True) - - if result.stderr: - print(f"{Colors.RED}Issues found:{Colors.ENDC}") - for line in result.stderr.split('\n')[:10]: # Show first 10 errors - if line.strip(): - print(f" {Colors.YELLOW}{line}{Colors.ENDC}") - logging.warning(f"File has errors: {result.stderr[:500]}") - return False - else: - print(f"{Colors.GREEN}No errors detected{Colors.ENDC}") - logging.info("File appears healthy") - return True - -def get_file_info(input_file): - """Get basic file info""" - cmd = [ - 'ffprobe', - '-v', 'error', - '-show_entries', 'format=duration,size:stream=codec_name,width,height', - '-of', 'json', - input_file - ] - result = subprocess.run(cmd, capture_output=True, text=True) - try: - return json.loads(result.stdout) - except: - return None - -def repair_method_1_remux(input_file, output_file): - """Method 1: Simple remux (copy streams to new container)""" - print(f"\n{Colors.BLUE}Trying Method 1: Remux (copy streams){Colors.ENDC}") - logging.info("Attempting repair method 1: Remux") - - cmd = [ - 'ffmpeg', - '-v', 'warning', - '-i', str(input_file), - '-c', 'copy', - '-map', '0', - '-y', - str(output_file) - ] - - try: - result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) - if result.returncode == 0 and Path(output_file).exists(): - print(f"{Colors.GREEN}Method 1 successful!{Colors.ENDC}") - logging.info("Method 1 successful") - return True - else: - print(f"{Colors.RED}Method 1 failed{Colors.ENDC}") - logging.warning(f"Method 1 failed: {result.stderr[:200]}") - return False - except Exception as e: - print(f"{Colors.RED}Method 1 error: {e}{Colors.ENDC}") - logging.error(f"Method 1 error: {e}") - return False - -def repair_method_2_error_concealment(input_file, output_file): - """Method 2: Remux with error concealment""" - print(f"\n{Colors.BLUE}Trying Method 2: Error concealment{Colors.ENDC}") - logging.info("Attempting repair method 2: Error concealment") - - cmd = [ - 'ffmpeg', - '-v', 'warning', - '-err_detect', 'ignore_err', - '-i', str(input_file), - '-c', 'copy', - '-map', '0', - '-fflags', '+genpts+igndts', - '-y', - str(output_file) - ] - - try: - result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) - if result.returncode == 0 and Path(output_file).exists(): - print(f"{Colors.GREEN}Method 2 successful!{Colors.ENDC}") - logging.info("Method 2 successful") - return True - else: - print(f"{Colors.RED}Method 2 failed{Colors.ENDC}") - logging.warning(f"Method 2 failed: {result.stderr[:200]}") - return False - except Exception as e: - print(f"{Colors.RED}Method 2 error: {e}{Colors.ENDC}") - logging.error(f"Method 2 error: {e}") - return False - -def repair_method_3_force_keyframes(input_file, output_file): - """Method 3: Force keyframe processing""" - print(f"\n{Colors.BLUE}Trying Method 3: Force keyframe processing{Colors.ENDC}") - logging.info("Attempting repair method 3: Force keyframe processing") - - cmd = [ - 'ffmpeg', - '-v', 'warning', - '-fflags', '+discardcorrupt+genpts', - '-i', str(input_file), - '-c', 'copy', - '-map', '0', - '-avoid_negative_ts', 'make_zero', - '-y', - str(output_file) - ] - - try: - result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) - if result.returncode == 0 and Path(output_file).exists(): - print(f"{Colors.GREEN}Method 3 successful!{Colors.ENDC}") - logging.info("Method 3 successful") - return True - else: - print(f"{Colors.RED}Method 3 failed{Colors.ENDC}") - logging.warning(f"Method 3 failed: {result.stderr[:200]}") - return False - except Exception as e: - print(f"{Colors.RED}Method 3 error: {e}{Colors.ENDC}") - logging.error(f"Method 3 error: {e}") - return False - -def repair_file(input_file, output_dir): - """Attempt to repair a damaged MP4 file""" - input_path = Path(input_file) - output_path = Path(output_dir) / f"{input_path.stem}_repaired{input_path.suffix}" - - print(f"\n{Colors.PURPLE}{'='*60}{Colors.ENDC}") - print(f"{Colors.PURPLE}Processing: {input_path.name}{Colors.ENDC}") - print(f"{Colors.PURPLE}{'='*60}{Colors.ENDC}") - - # Skip if already repaired - if output_path.exists(): - print(f"{Colors.YELLOW}Already repaired: {output_path.name}{Colors.ENDC}") - logging.info(f"Skipping {input_path} - already repaired") - return - - # Check file health first - is_healthy = check_file_health(str(input_path)) - - if is_healthy: - print(f"{Colors.GREEN}File appears healthy, no repair needed{Colors.ENDC}") - logging.info("File is healthy, skipping") - return - - # Try repair methods in sequence - methods = [ - repair_method_1_remux, - repair_method_2_error_concealment, - repair_method_3_force_keyframes - ] - - for method in methods: - if method(str(input_path), str(output_path)): - # Verify the repaired file - print(f"\n{Colors.BLUE}Verifying repaired file...{Colors.ENDC}") - if check_file_health(str(output_path)): - print(f"{Colors.GREEN}✓ Repair successful and verified!{Colors.ENDC}") - logging.info(f"Successfully repaired: {output_path}") - - # Show size comparison - original_size = input_path.stat().st_size / (1024*1024) - repaired_size = output_path.stat().st_size / (1024*1024) - print(f"Original: {original_size:.2f} MB → Repaired: {repaired_size:.2f} MB") - logging.info(f"Size: {original_size:.2f} MB → {repaired_size:.2f} MB") - return - else: - print(f"{Colors.YELLOW}Repair completed but file still has issues{Colors.ENDC}") - logging.warning("Repaired file still has issues") - return - - print(f"{Colors.RED}All repair methods failed{Colors.ENDC}") - logging.error(f"Failed to repair: {input_path}") - -if __name__ == "__main__": - input_dir = "input" - output_dir = "output" - os.makedirs(output_dir, exist_ok=True) - - # Get list of MP4 files - files = [f for f in os.listdir(input_dir) if f.endswith(('.mp4', '.DVR.mp4'))] - total_files = len(files) - - if total_files == 0: - print(f"{Colors.YELLOW}No MP4 files found in input directory{Colors.ENDC}") - logging.info("No files to process") - else: - print(f"\n{Colors.BLUE}Found {total_files} MP4 files to check{Colors.ENDC}") - logging.info(f"Found {total_files} files to process") - - for i, file in enumerate(files, 1): - input_file = os.path.join(input_dir, file) - print(f"\n{Colors.BLUE}[{i}/{total_files}]{Colors.ENDC}") - repair_file(input_file, output_dir) - - print(f"\n{Colors.GREEN}{'='*60}{Colors.ENDC}") - print(f"{Colors.GREEN}Repair process complete!{Colors.ENDC}") - print(f"{Colors.GREEN}Check the output directory for repaired files{Colors.ENDC}") - print(f"{Colors.GREEN}Log file: {log_file}{Colors.ENDC}") - print(f"{Colors.GREEN}{'='*60}{Colors.ENDC}") - - -