-
-
Save spolo96/0ac981dee92f9b16d54a4a1dde713aff to your computer and use it in GitHub Desktop.
An example Python code for compressing video file to target size.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import ffmpeg | |
def compress_video(video_full_path, size_upper_bound, two_pass=True, filename_suffix='1'): | |
""" | |
Compress video file to max-supported size. | |
:param video_full_path: the video you want to compress. | |
:param size_upper_bound: Max video size in KB. | |
:param two_pass: Set to True to enable two-pass calculation. | |
:param filename_suffix: Add a suffix for new video. | |
:return: out_put_name or error | |
""" | |
filename, extension = os.path.splitext(video_full_path) | |
extension = '.mp4' | |
output_file_name = filename + filename_suffix + extension | |
total_bitrate_lower_bound = 11000 | |
min_audio_bitrate = 32000 | |
max_audio_bitrate = 256000 | |
min_video_bitrate = 100000 | |
try: | |
# Bitrate reference: https://en.wikipedia.org/wiki/Bit_rate#Encoding_bit_rate | |
probe = ffmpeg.probe(video_full_path) | |
# Video duration, in s. | |
duration = float(probe['format']['duration']) | |
# Audio bitrate, in bps. | |
audio_bitrate = float(next((s for s in probe['streams'] if s['codec_type'] == 'audio'), None)['bit_rate']) | |
# Target total bitrate, in bps. | |
target_total_bitrate = (size_upper_bound * 1024 * 8) / (1.073741824 * duration) | |
if target_total_bitrate < total_bitrate_lower_bound: | |
print('Bitrate is extremely low! Stop compress!') | |
return False | |
# Best min size, in kB. | |
best_min_size = (min_audio_bitrate + min_video_bitrate) * (1.073741824 * duration) / (8 * 1024) | |
if size_upper_bound < best_min_size: | |
print('Quality not good! Recommended minimum size:', '{:,}'.format(int(best_min_size)), 'KB.') | |
# return False | |
# Target audio bitrate, in bps. | |
audio_bitrate = audio_bitrate | |
# target audio bitrate, in bps | |
if 10 * audio_bitrate > target_total_bitrate: | |
audio_bitrate = target_total_bitrate / 10 | |
if audio_bitrate < min_audio_bitrate < target_total_bitrate: | |
audio_bitrate = min_audio_bitrate | |
elif audio_bitrate > max_audio_bitrate: | |
audio_bitrate = max_audio_bitrate | |
# Target video bitrate, in bps. | |
video_bitrate = target_total_bitrate - audio_bitrate | |
if video_bitrate < 1000: | |
print('Bitrate {} is extremely low! Stop compress.'.format(video_bitrate)) | |
return False | |
i = ffmpeg.input(video_full_path) | |
if two_pass: | |
ffmpeg.output(i, '/dev/null' if os.path.exists('/dev/null') else 'NUL', | |
**{'c:v': 'libx264', 'b:v': video_bitrate, 'pass': 1, 'f': 'mp4'} | |
).overwrite_output().run() | |
ffmpeg.output(i, output_file_name, | |
**{'c:v': 'libx264', 'b:v': video_bitrate, 'pass': 2, 'c:a': 'aac', 'b:a': audio_bitrate} | |
).overwrite_output().run() | |
else: | |
ffmpeg.output(i, output_file_name, | |
**{'c:v': 'libx264', 'b:v': video_bitrate, 'c:a': 'aac', 'b:a': audio_bitrate} | |
).overwrite_output().run() | |
if os.path.getsize(output_file_name) <= size_upper_bound * 1024: | |
return output_file_name | |
elif os.path.getsize(output_file_name) < os.path.getsize(video_full_path): # Do it again | |
return compress_video(output_file_name, size_upper_bound) | |
else: | |
return False | |
except FileNotFoundError as e: | |
print('You do not have ffmpeg installed!', e) | |
print('You can install ffmpeg by reading https://github.com/kkroening/ffmpeg-python/issues/251') | |
return False | |
if __name__ == '__main__': | |
file_name = compress_video('input.mp4', 50 * 1000) | |
print(file_name) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment