Update app.py
Browse files
app.py
CHANGED
|
@@ -6,6 +6,15 @@ from pathlib import Path
|
|
| 6 |
import shutil
|
| 7 |
import json
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
def compress_video(
|
| 10 |
input_video,
|
| 11 |
resolution,
|
|
@@ -38,6 +47,23 @@ def compress_video(
|
|
| 38 |
output_ext = f".{output_format.lower()}"
|
| 39 |
output_path = input_path.replace(Path(input_video).suffix, f"_compressed{output_ext}")
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
# Build FFmpeg command
|
| 42 |
cmd = ["ffmpeg"]
|
| 43 |
|
|
@@ -65,8 +91,12 @@ def compress_video(
|
|
| 65 |
"1440p": "scale=-1:1440",
|
| 66 |
"4K": "scale=-1:2160"
|
| 67 |
}
|
|
|
|
| 68 |
if resolution != "Original":
|
| 69 |
vf_filters.append(scale_map[resolution])
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
# Rotation
|
| 72 |
if rotate != "None":
|
|
@@ -98,6 +128,11 @@ def compress_video(
|
|
| 98 |
crf_map = {"Low": 32, "Medium": 28, "High": 24, "Ultra High": 20}
|
| 99 |
crf = crf_map[quality]
|
| 100 |
cmd.extend(["-c:v", video_codec, "-crf", str(crf)])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
else:
|
| 102 |
cmd.extend(["-c:v", video_codec])
|
| 103 |
|
|
@@ -123,13 +158,16 @@ def compress_video(
|
|
| 123 |
cmd.extend(["-pass", "2"])
|
| 124 |
|
| 125 |
# Audio settings
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
cmd.extend(["-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
| 133 |
|
| 134 |
# Remove metadata
|
| 135 |
if remove_metadata:
|
|
@@ -204,7 +242,17 @@ def compress_video(
|
|
| 204 |
return output_path, info_text
|
| 205 |
|
| 206 |
except subprocess.CalledProcessError as e:
|
| 207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
except Exception as e:
|
| 209 |
return None, f"❌ An error occurred: {str(e)}"
|
| 210 |
finally:
|
|
|
|
| 6 |
import shutil
|
| 7 |
import json
|
| 8 |
|
| 9 |
+
def adjust_dimensions(width, height, codec):
|
| 10 |
+
"""Adjust dimensions to be compatible with the codec's requirements"""
|
| 11 |
+
if codec in ["libx265", "libvpx-vp9"]:
|
| 12 |
+
# These codecs require dimensions to be multiples of 8
|
| 13 |
+
new_width = (width + 7) // 8 * 8
|
| 14 |
+
new_height = (height + 7) // 8 * 8
|
| 15 |
+
return new_width, new_height
|
| 16 |
+
return width, height
|
| 17 |
+
|
| 18 |
def compress_video(
|
| 19 |
input_video,
|
| 20 |
resolution,
|
|
|
|
| 47 |
output_ext = f".{output_format.lower()}"
|
| 48 |
output_path = input_path.replace(Path(input_video).suffix, f"_compressed{output_ext}")
|
| 49 |
|
| 50 |
+
# Get video info to check dimensions
|
| 51 |
+
info_cmd = ["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", input_path]
|
| 52 |
+
probe_result = subprocess.run(info_cmd, capture_output=True, text=True)
|
| 53 |
+
video_info = json.loads(probe_result.stdout)
|
| 54 |
+
|
| 55 |
+
# Extract video stream info
|
| 56 |
+
video_stream = next((s for s in video_info["streams"] if s["codec_type"] == "video"), None)
|
| 57 |
+
if video_stream:
|
| 58 |
+
width = video_stream.get("width", 0)
|
| 59 |
+
height = video_stream.get("height", 0)
|
| 60 |
+
|
| 61 |
+
# Adjust dimensions if needed
|
| 62 |
+
new_width, new_height = adjust_dimensions(width, height, video_codec)
|
| 63 |
+
needs_resize = (new_width != width or new_height != height)
|
| 64 |
+
else:
|
| 65 |
+
needs_resize = False
|
| 66 |
+
|
| 67 |
# Build FFmpeg command
|
| 68 |
cmd = ["ffmpeg"]
|
| 69 |
|
|
|
|
| 91 |
"1440p": "scale=-1:1440",
|
| 92 |
"4K": "scale=-1:2160"
|
| 93 |
}
|
| 94 |
+
|
| 95 |
if resolution != "Original":
|
| 96 |
vf_filters.append(scale_map[resolution])
|
| 97 |
+
elif needs_resize:
|
| 98 |
+
# If we need to adjust dimensions for codec compatibility
|
| 99 |
+
vf_filters.append(f"scale={new_width}:{new_height}")
|
| 100 |
|
| 101 |
# Rotation
|
| 102 |
if rotate != "None":
|
|
|
|
| 128 |
crf_map = {"Low": 32, "Medium": 28, "High": 24, "Ultra High": 20}
|
| 129 |
crf = crf_map[quality]
|
| 130 |
cmd.extend(["-c:v", video_codec, "-crf", str(crf)])
|
| 131 |
+
elif video_codec == "libvpx-vp9":
|
| 132 |
+
# Map quality to CRF for VP9
|
| 133 |
+
crf_map = {"Low": 31, "Medium": 26, "High": 21, "Ultra High": 15}
|
| 134 |
+
crf = crf_map[quality]
|
| 135 |
+
cmd.extend(["-c:v", video_codec, "-crf", str(crf), "-b:v", "0"])
|
| 136 |
else:
|
| 137 |
cmd.extend(["-c:v", video_codec])
|
| 138 |
|
|
|
|
| 158 |
cmd.extend(["-pass", "2"])
|
| 159 |
|
| 160 |
# Audio settings
|
| 161 |
+
if audio_codec == "copy":
|
| 162 |
+
cmd.extend(["-c:a", "copy"])
|
| 163 |
+
else:
|
| 164 |
+
cmd.extend(["-c:a", audio_codec])
|
| 165 |
+
|
| 166 |
+
if audio_bitrate != "Auto":
|
| 167 |
+
cmd.extend(["-b:a", audio_bitrate])
|
| 168 |
+
|
| 169 |
+
if audio_sample_rate != "Original":
|
| 170 |
+
cmd.extend(["-ar", audio_sample_rate])
|
| 171 |
|
| 172 |
# Remove metadata
|
| 173 |
if remove_metadata:
|
|
|
|
| 242 |
return output_path, info_text
|
| 243 |
|
| 244 |
except subprocess.CalledProcessError as e:
|
| 245 |
+
error_message = e.stderr
|
| 246 |
+
|
| 247 |
+
# Check for specific error conditions
|
| 248 |
+
if "Picture width must be an integer multiple" in error_message:
|
| 249 |
+
error_message = "The video dimensions are not compatible with the selected codec. The app will try to adjust the dimensions automatically."
|
| 250 |
+
elif "Cannot open libx265 encoder" in error_message:
|
| 251 |
+
error_message = "Error with H.265 encoding. Try using H.264 instead."
|
| 252 |
+
elif "Unsupported codec" in error_message:
|
| 253 |
+
error_message = "The selected codec is not supported. Try a different codec."
|
| 254 |
+
|
| 255 |
+
return None, f"❌ Compression failed: {error_message}"
|
| 256 |
except Exception as e:
|
| 257 |
return None, f"❌ An error occurred: {str(e)}"
|
| 258 |
finally:
|