import gradio as gr import subprocess import os #import spaces 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 #@spaces.GPU(duration=120) 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", #"-hwaccel", #"cuda", "-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) Thanks for [this article](https://huggingface.co/posts/luigi12345/403914274386316) for providing the formula """) 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(debug=True, show_error=True)