diff --git a/app.py b/app.py
index 829d1f5..f8efdc4 100644
--- a/app.py
+++ b/app.py
@@ -157,11 +157,16 @@ def process_video():
if mute_audio:
cmd.extend(['-an']) # Remove audio
+ # Get quality (CRF value)
+ quality = data.get('quality', 23)
+ # Ensure quality is within valid range (18-32)
+ quality = max(18, min(32, int(quality)))
+
# Output settings for H.264 MP4
cmd.extend([
'-c:v', 'libx264',
'-preset', 'medium',
- '-crf', '23',
+ '-crf', str(quality),
'-c:a', 'aac',
'-b:a', '128k',
'-movflags', '+faststart',
diff --git a/templates/index.html b/templates/index.html
index b7bd9f0..74c52aa 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -588,6 +588,28 @@
+
+
+
@@ -632,6 +654,7 @@
let scalePercentage = 100;
let rotationDegrees = 0;
let muteAudio = false;
+ let compressionQuality = 23;
// Upload area handling
const uploadArea = document.getElementById('upload-area');
@@ -935,6 +958,9 @@
const scaleSlider = document.getElementById('scale-slider');
const scaleValueDisplay = document.getElementById('scale-value-display');
const outputResolution = document.getElementById('output-resolution');
+ const qualitySlider = document.getElementById('quality-slider');
+ const qualityValueDisplay = document.getElementById('quality-value-display');
+ const crfValueDisplay = document.getElementById('crf-value-display');
function updateScaleDisplay() {
scalePercentage = parseInt(scaleSlider.value);
@@ -953,14 +979,40 @@
scaleSlider.addEventListener('input', updateScaleDisplay);
+ // Quality slider
+ function updateQualityDisplay() {
+ compressionQuality = parseInt(qualitySlider.value);
+ crfValueDisplay.textContent = compressionQuality;
+
+ // Update quality label
+ let qualityLabel = 'Balanced';
+ if (compressionQuality <= 19) qualityLabel = 'Best Quality';
+ else if (compressionQuality <= 22) qualityLabel = 'High';
+ else if (compressionQuality <= 25) qualityLabel = 'Balanced';
+ else if (compressionQuality <= 28) qualityLabel = 'Low';
+ else qualityLabel = 'Smallest File';
+
+ qualityValueDisplay.textContent = qualityLabel;
+ }
+
+ qualitySlider.addEventListener('input', updateQualityDisplay);
+ updateQualityDisplay();
+
// Scale presets
document.querySelectorAll('.preset-btn').forEach(btn => {
btn.addEventListener('click', () => {
const scale = btn.dataset.scale;
+ const quality = btn.dataset.quality;
+
if (scale) {
scaleSlider.value = scale;
updateScaleDisplay();
}
+
+ if (quality) {
+ qualitySlider.value = quality;
+ updateQualityDisplay();
+ }
});
});
@@ -984,7 +1036,8 @@
end_time: endTime,
scale_percentage: scalePercentage,
rotation: rotationDegrees,
- mute_audio: muteAudio
+ mute_audio: muteAudio,
+ quality: compressionQuality
};
if (cropWidth > 0 && cropHeight > 0) {
@@ -1048,8 +1101,9 @@
rotationDegrees = 0;
muteAudio = false;
scalePercentage = 100;
+ compressionQuality = 23;
- videoPreview.src = '';
+ videoPreview.src = '';;
videoInput.value = '';
clearCropCanvas();
cropCanvas.classList.remove('active');
@@ -1065,6 +1119,8 @@
document.getElementById('scale-value-display').textContent = '100%';
document.getElementById('output-resolution').textContent = '--';
document.getElementById('current-time-display').textContent = '0:00';
+ document.getElementById('quality-slider').value = '23';
+ updateQualityDisplay();
// Reset quick actions
document.getElementById('mute-audio-btn').classList.remove('active');