Spaces:
Running
Running
| import gradio as gr | |
| import subprocess | |
| import os | |
| def get_file_size(file_path): | |
| """Get file size in a human-readable format""" | |
| if not file_path or not os.path.exists(file_path): | |
| return "N/A" | |
| size_bytes = os.path.getsize(file_path) | |
| # Convert to appropriate unit | |
| for unit in ['B', 'KB', 'MB', 'GB']: | |
| if size_bytes < 1024 or unit == 'GB': | |
| return f"{size_bytes:.2f} {unit}" | |
| size_bytes /= 1024 | |
| def compress_video(video_file): | |
| """Compresses the uploaded video using FFmpeg and returns the output video path and file sizes.""" | |
| if video_file is None: | |
| gr.Info("No video uploaded") | |
| return None, "N/A", "N/A", 0 | |
| try: | |
| # Get the input file path and size | |
| input_path = video_file | |
| input_size = get_file_size(input_path) | |
| # Create output filename - in the same directory as input | |
| base_dir = os.path.dirname(input_path) | |
| filename = os.path.basename(input_path) | |
| name, ext = os.path.splitext(filename) | |
| output_path = os.path.join(base_dir, f"{name}_compressed{ext}") | |
| # Execute ffmpeg command | |
| command = [ | |
| "ffmpeg", | |
| "-i", input_path, | |
| "-vcodec", "libx264", | |
| "-crf", "28", | |
| "-vf", "pad=ceil(iw/2)*2:ceil(ih/2)*2", | |
| "-y", | |
| output_path | |
| ] | |
| # Show processing notification | |
| gr.Info("Processing video...") | |
| # Run the command | |
| process = subprocess.Popen( | |
| command, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE | |
| ) | |
| stdout, stderr = process.communicate() | |
| if process.returncode != 0: | |
| error_message = stderr.decode() | |
| gr.Info(f"Error: FFmpeg operation failed. Error message: {error_message}") | |
| return None, input_size, "N/A", 0 | |
| # Calculate output size and savings | |
| output_size = get_file_size(output_path) | |
| # Calculate compression percentage | |
| input_bytes = os.path.getsize(input_path) | |
| output_bytes = os.path.getsize(output_path) | |
| if input_bytes > 0: | |
| compression_percent = (1 - (output_bytes / input_bytes)) * 100 | |
| else: | |
| compression_percent = 0 | |
| # Show success notification | |
| gr.Info(f"Video compressed successfully! Saved {compression_percent:.1f}% of original size") | |
| # Return the processed video file and size information | |
| return output_path, input_size, output_size, round(compression_percent, 1) | |
| except Exception as e: | |
| gr.Info(f"An error occurred: {str(e)}") | |
| return None, get_file_size(video_file) if video_file else "N/A", "N/A", 0 | |
| with gr.Blocks(theme=gr.themes.Soft()) as app: | |
| gr.Markdown("# Video Compression with FFmpeg") | |
| gr.Markdown(""" | |
| - Uses H.264 codec | |
| - CRF 28 (higher values = more compression, lower quality) | |
| - Pads dimensions to ensure they're even numbers (required by some codecs) | |
| """) | |
| with gr.Row(): | |
| with gr.Column(): | |
| input_video = gr.Video(label="Upload Video") | |
| input_size_display = gr.Textbox(label="Input File Size", interactive=False) | |
| compress_btn = gr.Button("Compress Video", variant="primary") | |
| with gr.Column(): | |
| output_video = gr.Video(label="Compressed Video") | |
| output_size_display = gr.Textbox(label="Output File Size", interactive=False) | |
| compression_ratio = gr.Number(label="Space Saved (%)", interactive=False) | |
| compress_btn.click( | |
| fn=compress_video, | |
| inputs=[input_video], | |
| outputs=[output_video, input_size_display, output_size_display, compression_ratio] | |
| ) | |
| # Also update input size when video is uploaded | |
| input_video.change( | |
| fn=lambda video: get_file_size(video) if video else "N/A", | |
| inputs=[input_video], | |
| outputs=[input_size_display] | |
| ) | |
| app.launch() | |