Pracuje s malými segmenty, které by měl kopírovat na ramdisk a pak je sloučí do jednoho zpomaleného videa. Zvuk jsem se snažil zachovat v původních tonech. Je možné dát tam více zpomalovacích faktorů.
#!/usr/bin/env python3
import os
# MoviePy 1.x importuje moduly takto:
from moviepy.editor import VideoFileClip, AudioFileClip, concatenate_videoclips, vfx
"""
MoviePy 2.x importuje moduly takto:
from moviepy import VideoFileClip, concatenate_videoclips
from moviepy.video.fx import all as vfx
from moviepy.audio.io import AudioFileClip
"""
import librosa
import soundfile as sf
import time
# Definice zdrojových a cílových adresářů
source_dirs = [
"./Jan Kudelka",
"./Zpěvník Znam i gram - T Stachak"
]
source_ext = "mkv"
# Faktory zpomalení
slowdowns = [4]
# Vytvoření RAM disku (bez skutečného připojení, pokud je ramdisk_disable = True)
ramdisk_disable = True # Deaktivuje vytvoření RAM disku
ramdisk_path = "./ramdisk" # Globální RAM disk pro všechny
log_file = "./ramdisk.log"
if not os.path.exists(ramdisk_path):
os.makedirs(ramdisk_path)
if not ramdisk_disable:
with open(log_file, "w") as log:
os.system(f'sudo mount -t tmpfs -o size={ramdisk_size}M tmpfs "{ramdisk_path}"')
os.system(f'df "{ramdisk_path}" > "{log_file}"')
with open(log_file, "r") as log:
log_content = log.read()
if ramdisk_path in log_content:
print(f"RAM disk is correctly mounted.")
else:
print(f"RAM disk is not found")
# Funkce pro změnu pitchu pomocí ffmpeg
def audio_pitchup_ffmpeg(input_audio_path, output_audio_path, factor):
command = f'ffmpeg -i "{input_audio_path}" -filter_complex "rubberband=pitch={factor}" "{output_audio_path}"'
os.system(command)
# Funkce pro změnu rychlosti zvuku pomocí librosa
def change_audio_speed(input_audio_path, output_audio_path, speed_factor, target_duration):
y, sr = librosa.load(input_audio_path, sr=None)
original_duration = librosa.get_duration(y=y, sr=sr)
print(f"Audio duration before stretching: {original_duration} seconds")
y_stretched = librosa.effects.time_stretch(y, rate=original_duration / target_duration)
stretched_duration = librosa.get_duration(y=y_stretched, sr=sr)
print(f"Audio duration after stretching: {stretched_duration} seconds")
time.sleep(2)
sf.write(output_audio_path, y_stretched, sr)
# Převod času na sekundy
def convert_to_seconds(time_str):
parts = time_str.split(':')
minutes = int(parts[0])
seconds = float(parts[1])
return minutes * 60 + seconds
# Definice časových rozsahů – automaticky po 20 sekundách
def generate_time_ranges(duration, segment_len=10.0):
ranges = []
start = 0.0
while start < duration:
end = min(start + segment_len, duration)
# Formát jako máš v kódu
start_str = f"{int(start // 60)}:{start % 60:05.2f}"
end_str = f"{int(end // 60)}:{end % 60:05.2f}"
ranges.append((start_str, end_str))
start = end
return ranges
# Definice časových rozsahů k vyexportování - nahrazeno funkcí generate_time_ranges()
time_ranges = [
("0:0.0", "0:10.00"),
("0:10.0", "0:20.00"),
("0:20.0", "0:30.00"),
("0:30.0", "0:40.00"),
("0:40.0", "0:50.00"),
("0:50.0", "0:60.00"),
("1:00.0", "1:10.00"),
("1:10.0", "1:20.00")
]
# Zpracování všech souborů v každém zdrojovém adresáři
for source_dir in source_dirs:
# Vytvoření výstupních složek dynamicky na základě faktorů zpomalení
output_dirs = [os.path.join(source_dir, str(factor)) for factor in slowdowns]
for dir in output_dirs:
os.makedirs(dir, exist_ok=True)
# Získání všech MP4 souborů ve zdrojovém adresáři
original_files = [f for f in os.listdir(source_dir) if f.endswith(f".{source_ext}")]
for file in original_files:
video_path = os.path.join(source_dir, file)
if os.path.isfile(video_path):
video_clip = VideoFileClip(video_path)
video_duration = video_clip.duration
print(f"Video {file}: délka {video_duration:.1f} s")
time_ranges = generate_time_ranges(video_duration, segment_len=10.0)
# Pro každý faktor zpomalení
for i, factor in enumerate(slowdowns):
segment_paths = []
# Zpracování jednotlivých segmentů
for j, (start_time, end_time) in enumerate(time_ranges):
start_seconds = convert_to_seconds(start_time)
end_seconds = convert_to_seconds(end_time)
# Kontrola, zda rozsah nepřesahuje délku videa
if start_seconds >= video_clip.duration:
continue
end_seconds = min(end_seconds, video_clip.duration)
# v 2.0
seg_clip = video_clip.subclip(start_seconds, end_seconds)
output_segment_path = os.path.join(ramdisk_path, f"segment_{j+1}_slow_{factor}.mp4")
# Zpracování zpomalení a pitch pro každý segment
segment_audio_path = os.path.join(ramdisk_path, f"segment_{j+1}_temp_audio.wav")
seg_clip.audio.write_audiofile(segment_audio_path, codec='pcm_s16le')
pitched_audio_path = os.path.join(ramdisk_path, f"segment_{j+1}_new_temp_audio.wav")
audio_pitchup_ffmpeg(segment_audio_path, pitched_audio_path, factor)
final_audio_path = os.path.join(ramdisk_path, f"segment_{j+1}_final_audio.wav")
change_audio_speed(pitched_audio_path, final_audio_path, factor, seg_clip.duration)
new_audio_clip = AudioFileClip(final_audio_path)
edited_clip = seg_clip.set_audio(new_audio_clip)
edited_clip = edited_clip.fx(vfx.speedx, 1.0 / factor)
edited_clip.set_duration(edited_clip.duration)
print(f"Processing segment {j+1} with slowdown factor {factor} for file {file}. Saving to {output_segment_path}")
edited_clip.write_videofile(output_segment_path, codec="libx264", audio_codec="aac")
segment_paths.append(output_segment_path)
edited_clip.close()
new_audio_clip.close()
# Odstranění dočasných souborů
os.remove(segment_audio_path)
os.remove(pitched_audio_path)
os.remove(final_audio_path)
# Sloučení zpracovaných segmentů do jednoho videa
if segment_paths:
output_path = os.path.join(output_dirs[i], file)
final_clip = concatenate_videoclips([VideoFileClip(seg) for seg in segment_paths])
final_clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
final_clip.close()
# Odstranění dočasných segmentů
for segment_path in segment_paths:
os.remove(segment_path)
print("Job done.")
if not ramdisk_disable:
os.system(f'sudo umount "{ramdisk_path}"')
Žádné komentáře:
Okomentovat