Skip to content

Instantly share code, notes, and snippets.

@gphg
Last active March 10, 2025 06:52
Show Gist options
  • Save gphg/37218243e9b71c59f41c75d05747ba34 to your computer and use it in GitHub Desktop.
Save gphg/37218243e9b71c59f41c75d05747ba34 to your computer and use it in GitHub Desktop.
GitHub Copilot assisted ffmpeg python script.
#!/usr/bin/python
import os
import subprocess
import sys
import time
def get_video_bitrate(input_file):
# Use ffprobe to get the video bitrate
ffprobe_command = [
'ffprobe',
'-v', 'error',
'-select_streams', 'v:0',
'-show_entries', 'stream=bit_rate',
'-of', 'default=noprint_wrappers=1:nokey=1',
input_file
]
result = subprocess.run(ffprobe_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
bitrate = int(result.stdout.decode().strip())
return bitrate
def convert_to_webm(input_file, output_file, max_size_mb, degration=0.9):
original_bitrate = get_video_bitrate(input_file)
rounded_bitrate = (original_bitrate // (1024 * 1024)) # Round down to nearest megabit
decrement_bitrate = rounded_bitrate * (1 - degration) # 10% of the original bitrate
print(f"Get video bitrate at {rounded_bitrate}M, formerly {original_bitrate}.")
# Use ffmpeg to convert the video to WebM format
ffmpeg_command = [
'ffmpeg',
'-i', input_file,
'-y', # Always overwrite!!!
'-c:v', 'libvpx-vp9', # Use VP9 codec
'-b:v', f'{rounded_bitrate}M', # Use rounded bitrate with 'M'
'-c:a', 'libopus', # Use Opus audio codec
'-b:a', '128k', # Set audio bitrate
'-speed', '0', # Targets maximum quality and lowest filesizes
#'-vf', 'scale=-1:1080',
output_file
]
start_time = time.time() # Timing, as video encoding taking minutes to hours
subprocess.run(ffmpeg_command)
# Check the size of the output file
file_size_mb = os.path.getsize(output_file) / (1024 * 1024)
# Track tries
n = 0
# Adjust bitrate if the file size exceeds the max size
while file_size_mb > max_size_mb:
n += 1
print(f"[attempt: {n}] Video size is {file_size_mb:.2f} MB, but expecting lower than {max_size_mb} MB.")
current_bitrate = rounded_bitrate - (decrement_bitrate * (n - 1))
new_bitrate = rounded_bitrate - (decrement_bitrate * n)
ffmpeg_command[7] = f'{new_bitrate}M'
print(f"[attempt: {n}] Reducing bitrate to {new_bitrate}M, formerly {current_bitrate}M.")
subprocess.run(ffmpeg_command)
file_size_mb = os.path.getsize(output_file) / (1024 * 1024)
elapsed = (time.time() - start_time)
print(f"File converted to {output_file} with size {file_size_mb:.2f} MB.")
print(f"Conversion done in {elapsed:.3f} seconds and {n} tries.")
return n, elapsed
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python to-webm.py <input_file> <output_file>")
sys.exit(1)
input_file = sys.argv[1]
if len(sys.argv) > 2:
output_file = sys.argv[2]
else:
filename = os.path.basename(input_file)
pre, ext = os.path.splitext(filename)
output_file = pre + ".webm"
# The max file size as allowed on webm.red
max_size_mb = 20.5
convert_to_webm(input_file, output_file, max_size_mb)
@gphg
Copy link
Author

gphg commented Mar 10, 2025

Yes, it sucks. Instead of video bitrate, I could just goes with CRF instead. What this script does is reencodes the same source into several settings, which might ended in really big numbers of attempt while CRF only 0-63 at most.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment