-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcompress.py
91 lines (79 loc) · 3.85 KB
/
compress.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import ffmpeg
import os
os.environ['path'] = 'bin/'
def compress_video(video_full_path, size_upper_bound, frame_rate=30, two_pass=False, filename_suffix='_compressed'):
"""
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 frame_rate: Set the video max frame per second.
:param two_pass: Set to True to enable two-pass calculation.
:param filename_suffix: Add a suffix for new video.
:return: True if succes, False if 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 = 64000
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',
**{'r': frame_rate, 'c:v': 'libx264', 'b:v': video_bitrate, 'pass': 1, 'f': 'mp4'}
).overwrite_output().run()
ffmpeg.output(i, output_file_name, **{'r': frame_rate, '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,
**{'r': frame_rate, '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 True
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)