Created
April 20, 2025 12:52
-
-
Save me-suzy/fdd36397b978b75edc661f300a3ddd1e to your computer and use it in GitHub Desktop.
Combina video si imagini cu sau fara muzica pe fundal (fara compresie video).py
This file contains hidden or 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
#!/usr/bin/env python3 | |
import os | |
import sys | |
from moviepy.editor import VideoFileClip, ImageClip, AudioFileClip, concatenate_videoclips, concatenate_audioclips | |
import re | |
import gc | |
import shutil | |
def get_video_info(clip): | |
return { | |
'durată': f"{clip.duration:.2f} secunde", | |
'dimensiune': f"{os.path.getsize(clip.filename)/(1024*1024):.1f} MB", | |
'rezoluție': f"{clip.size[0]}x{clip.size[1]}", | |
'fps': f"{clip.fps}" | |
} | |
def process_video_compression(video_clip, output_file, target_bitrate, original_size): | |
try: | |
video_clip.write_videofile( | |
output_file, | |
fps=video_clip.fps, | |
codec='libx264', | |
audio_codec='aac', | |
temp_audiofile='temp-audio.m4a', | |
remove_temp=True, | |
bitrate=f"{target_bitrate/1000:.0f}k", | |
preset="medium", | |
threads=4, | |
audio_bitrate="192k", | |
ffmpeg_params=[ | |
"-crf", "18", | |
"-movflags", "+faststart", | |
"-profile:v", "high", | |
"-level", "4.1", | |
"-pix_fmt", "yuv420p", | |
"-tune", "film", | |
"-maxrate", f"{target_bitrate*1.5/1000:.0f}k", | |
"-bufsize", f"{target_bitrate*2/1000:.0f}k", | |
"-max_muxing_queue_size", "9999" | |
] | |
) | |
final_size = os.path.getsize(output_file) | |
compression_ratio = (1 - final_size/original_size) * 100 | |
print("\n=== Rezultate Compresie ===") | |
print(f"Dimensiune originală: {original_size/(1024*1024):.1f} MB") | |
print(f"Dimensiune după compresie: {final_size/(1024*1024):.1f} MB") | |
print(f"Rata de compresie: {compression_ratio:.1f}%") | |
return True | |
except Exception as e: | |
print(f"\n❌ Eroare la compresie: {str(e)}") | |
return False | |
finally: | |
if os.path.exists('temp-audio.m4a'): | |
os.remove('temp-audio.m4a') | |
gc.collect() | |
def process_file_individually(file_path, output_dir, index, target_size=None): | |
"""Procesează fiecare fișier separat, păstrând dimensiunea originală sau ajustând-o cu padding""" | |
temp_output = os.path.join(output_dir, f"temp_processed_{index}.mp4") | |
try: | |
if file_path.lower().endswith(('.mp4')): | |
clip = VideoFileClip(file_path) | |
original_fps = clip.fps | |
else: | |
img = ImageClip(file_path) | |
original_fps = 24 | |
clip = img.set_duration(5).set_fps(original_fps) | |
if target_size: | |
clip = clip.resize(newsize=target_size) if clip.size != target_size else clip | |
if clip.size != target_size: | |
clip = clip.on_color(size=target_size, color=(0, 0, 0), pos='center') | |
clip.write_videofile( | |
temp_output, | |
fps=original_fps, | |
codec='libx264', | |
audio_codec='aac', | |
preset="medium", | |
ffmpeg_params=[ | |
"-crf", "18", | |
"-max_muxing_queue_size", "9999" | |
] | |
) | |
clip.close() | |
gc.collect() | |
return temp_output, original_fps | |
except Exception as e: | |
print(f"\n❌ Eroare la procesarea fișierului: {str(e)}") | |
return None, None | |
def combine_and_compress_media(input_directory, output_file, audio_files=None, image_duration=5): | |
try: | |
media_files = [ | |
f for f in os.listdir(input_directory) | |
if f.lower().endswith(('.mp4', '.jpg', '.jpeg', '.png')) | |
] | |
if not media_files: | |
print("❌ Nu s-au găsit fișiere media în director!") | |
return False | |
media_files.sort(key=lambda s: [ | |
int(t) if t.isdigit() else t.lower() | |
for t in re.split('([0-9]+)', s) | |
]) | |
print("\nFișiere găsite:", ", ".join(media_files)) | |
# Definim un director temporar personalizat | |
temp_dir = os.path.join(input_directory, "Temp") | |
if not os.path.exists(temp_dir): | |
os.makedirs(temp_dir) # Creăm directorul dacă nu există | |
print(f"Director temporar: {temp_dir}") | |
processed_files = [] | |
total_size = 0 | |
resolutions = [] | |
fps_values = [] | |
for file in media_files: | |
full_path = os.path.join(input_directory, file) | |
if file.lower().endswith(('.mp4')): | |
clip = VideoFileClip(full_path) | |
resolutions.append(clip.size) | |
fps_values.append(clip.fps) | |
clip.close() | |
else: | |
img = ImageClip(full_path) | |
resolutions.append(img.size) | |
fps_values.append(24) | |
img.close() | |
gc.collect() | |
target_width = max([res[0] for res in resolutions]) | |
target_height = max([res[1] for res in resolutions]) | |
target_size = (target_width, target_height) | |
target_fps = max(fps_values) | |
print(f"\nRezoluție țintă: {target_size}, FPS țintă: {target_fps}") | |
for idx, file in enumerate(media_files): | |
print(f"\nProcesez: {file}") | |
full_path = os.path.join(input_directory, file) | |
total_size += os.path.getsize(full_path) | |
temp_file, fps = process_file_individually(full_path, temp_dir, idx, target_size=target_size) | |
if temp_file: | |
processed_files.append(temp_file) | |
else: | |
print(f"Eroare la procesarea {file}, continui cu următorul...") | |
if not processed_files: | |
print("Nu s-au putut procesa fișierele media!") | |
return False | |
concat_file = os.path.join(temp_dir, "concat_list.txt") | |
with open(concat_file, 'w') as f: | |
for file in processed_files: | |
f.write(f"file '{file}'\n") | |
temp_combined = os.path.join(temp_dir, "combined_video.mp4") | |
os.system(f'ffmpeg -f concat -safe 0 -i "{concat_file}" -c copy "{temp_combined}"') | |
if not os.path.exists(temp_combined): | |
print("❌ Nu s-a putut crea fișierul combinat!") | |
return False | |
has_audio = False | |
video_to_compress = VideoFileClip(temp_combined) | |
if audio_files: | |
valid_audio = [a for a in audio_files if a and os.path.exists(a)] | |
if valid_audio: | |
print("🎵 Adaug fișiere audio pe fundal...") | |
has_audio = True | |
audio_clips = [] | |
current_duration = 0 | |
while current_duration < video_to_compress.duration: | |
for audio_file in valid_audio: | |
if current_duration >= video_to_compress.duration: | |
break | |
audio = AudioFileClip(audio_file) | |
remaining = video_to_compress.duration - current_duration | |
if audio.duration > remaining: | |
audio = audio.subclip(0, remaining) | |
audio_clips.append(audio) | |
current_duration += audio.duration | |
if audio_clips: | |
final_audio = concatenate_audioclips(audio_clips) | |
video_to_compress = video_to_compress.set_audio(final_audio) | |
print("📦 Comprim video-ul final...") | |
success = process_video_compression(video_to_compress, output_file, 5000*1000, total_size) | |
video_to_compress.close() | |
return success | |
except Exception as e: | |
print(f"❌ Eroare: {str(e)}") | |
return False | |
finally: | |
try: | |
# Nu ștergem directorul Temp, dar putem șterge fișierele temporare create | |
for file in os.listdir(temp_dir): | |
file_path = os.path.join(temp_dir, file) | |
if os.path.isfile(file_path): | |
os.remove(file_path) | |
except: | |
pass | |
gc.collect() | |
def main(): | |
INPUT_PATH = r"g:\Dubai Nou\METRO DUBAI" | |
AUDIO_FILES = [ | |
r"G:\Muzica\Andorra - A Song For Harmony (Original Mix) (320kbps).mp3", | |
r"G:\Muzica\Andorra - A Song For Harmony (Original Mix) (320kbps).mp3" | |
] | |
# Pentru a salva fără audio, setează: | |
# AUDIO_FILES = [ | |
# r"", | |
# r"" | |
# ] | |
AUDIO_FILES = [af for af in AUDIO_FILES if af] | |
output_file = os.path.join(INPUT_PATH, "FISIER-SALVAT.mp4") | |
success = combine_and_compress_media(INPUT_PATH, output_file, AUDIO_FILES, image_duration=5) | |
if success: | |
print("\n✅ Procesul s-a finalizat cu succes!") | |
else: | |
print("\n❌ Procesul a eșuat!") | |
if __name__ == "__main__": | |
gc.collect() | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment