-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompress_video.py
More file actions
90 lines (76 loc) · 2.86 KB
/
compress_video.py
File metadata and controls
90 lines (76 loc) · 2.86 KB
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
#!/usr/bin/python3
#
# Script by EmmetJoe009: https://pastebin.com/t3Bh2kNU
# /// script
# requires-python = ">=3.9"
# ///
import sys
import subprocess
import os
import argparse
import time
startTime: float = time.time()
parser: argparse.ArgumentParser = argparse.ArgumentParser()
parser.add_argument('-f', '--file', help='File to Crush', required=True)
parser.add_argument('-o', '--output', help='Output File', required=False)
parser.add_argument("-s", "--size", help="Target Size in MB", type=int, default=8)
parser.add_argument("-t", "--tolerance", help="Tolerance", type=int, default=10)
args: argparse.Namespace = parser.parse_args()
def get_duration(fileInput: str) -> float:
return float(
subprocess.check_output([
"ffprobe",
"-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
fileInput
])[:-1]
)
def transcode(fileInput: str, fileOutput: str, bitrate: int) -> None:
command: list[str] = [
'ffmpeg',
'-y',
'-hide_banner',
'-loglevel', 'error',
'-i', fileInput,
'-b', str(bitrate) + '',
'-cpu-used', str(os.cpu_count()),
'-c:a',
'copy',
fileOutput
]
proc: subprocess.CompletedProcess[str] = subprocess.run(
command,
capture_output=True,
# avoid having to explicitly encode
text=True
)
tolerance: int = args.tolerance
fileInput: str = args.file
if args.output:
fileOutput: str = args.output
else:
fileOutput: str = fileInput[:fileInput.rindex('.')] + '.crushed' + fileInput[fileInput.rindex('.'):]
targetSizeKilobytes: int = args.size * 1024
targetSizeBytes: int = targetSizeKilobytes * 1024
durationSeconds: float = get_duration(fileInput)
bitrate: int = round(targetSizeBytes / durationSeconds)
beforeSizeBytes: int = os.stat(fileInput).st_size
print(f"Crushing {fileInput} to {targetSizeKilobytes} KB with tolerance {tolerance}%")
factor: float = 0
attempt: int = 0
while (factor > 1.0 + (tolerance / 100)) or (factor < 1):
attempt = attempt + 1
bitrate = round(bitrate * (factor or 1))
print(f"Attempt {attempt}: Transcoding {fileInput} at bitrate {bitrate}")
transcode(fileInput, fileOutput, bitrate)
afterSizeBytes: int = os.stat(fileOutput).st_size
percentOfTarget: float = (100 / targetSizeBytes) * afterSizeBytes
factor = 100 / percentOfTarget
print(
f"Attempt {attempt}: Original size: {beforeSizeBytes / 1024 / 1024:.2f} MB, "
f"New size: {afterSizeBytes / 1024 / 1024:.2f} MB, "
f"Percentage of target: {percentOfTarget:.0f}% and bitrate {bitrate}"
)
print(f"Completed in {attempt} attempts over {round(time.time() - startTime, 2)} seconds")
print(f" > Exported as {fileOutput}")