[Python] Failed to add audio to mp4 with moviepy

Discussão em 'Python' iniciado por Stack, Abril 24, 2025.

  1. Stack

    Stack Membro Participativo

    I generated an audio sound.wav and a video temp.mp4 that makes use of the audio. Both with the same duration.

    I got the following warning when generating the temp.mp4. The animation is out of sync, it means that it freezes before the audio finishes.


    .venv\Lib\site-packages\moviepy\video\io\ffmpeg_reader.py:178: UserWarning: In file temp.mp4, 1080000 bytes wanted but 0 bytes read at frame index 299 (out of a total 300 frames), at time 4.98/5.00 sec. Using the last valid frame instead. warnings.warn(
    ​

    Complete code:

    # to generate sound.wav
    import numpy as np
    import soundfile as sf
    from tqdm import tqdm
    from os import startfile

    # Parameters
    filename = "sound.wav"
    duration = 5 # seconds
    num_voices = 1000
    sample_rate = 44100 # Hz
    chunk_size = sample_rate # write in 1-second chunks


    t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)

    # Create many detuned sine waves (Deep Note style)
    start_freqs = np.random.uniform(100, 400, num_voices)
    end_freqs = np.linspace(400, 800, num_voices) # target harmony

    # Each voice sweeps from start to end frequency
    signal = np.zeros_like(t)
    for i in range(num_voices):
    freqs = np.linspace(start_freqs, end_freqs, t.size)
    voice = np.sin(2 * np.pi * freqs * t)
    voice *= np.sin(np.pi * i / num_voices) # slight variance
    signal += voice

    # Volume envelope
    envelope = np.linspace(0.01, 1.0, t.size)
    signal *= envelope

    # Normalize
    signal /= np.max(np.abs(signal))

    # Save with progress bar using soundfile
    with sf.SoundFile(
    filename, "w", samplerate=sample_rate, channels=1, subtype="PCM_16"
    ) as f:
    for i in tqdm(range(0, len(signal), chunk_size), desc=f"Saving {filename}"):
    f.write(signal[i : i + chunk_size])


    startfile(filename)


    # to generate temp.mp4
    from numpy import pi, sin, cos
    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    from os import startfile
    from tqdm import tqdm
    from moviepy import VideoFileClip, AudioFileClip, CompositeAudioClip

    # Output settings
    filename = "temp.mp4"
    duration = 5 # seconds of animation
    maxdim = 4 # canvas size in plot units (scaled)
    fps = 60

    # Real-world parameters
    r = 40 # km (radius)
    endtime = 2 # hours (duration of real motion)
    rph = 0.5 # rotations per hour
    omega = 2 * pi * rph # rad/hour
    speed = omega * r # km/hour

    # Animation setup
    frames = duration * fps
    scale = maxdim / r # scale from km to plot units
    dt = endtime / frames # time per frame in hours

    # Prepare figure and axes
    fig, ax = plt.subplots(figsize=(6, 6))
    ax.set_xlim(-maxdim - 1, maxdim + 1)
    ax.set_ylim(-maxdim - 1, maxdim + 1)
    ax.set_aspect("equal")
    ax.grid()



    # Plot circle path
    circle = plt.Circle((0, 0), r * scale, color="lightgray", fill=False, linestyle="--")
    ax.add_patch(circle)

    # Moving point
    (point,) = ax.plot([], [], "ro")

    # Info text at center of the circle
    info_text = ax.text(
    0, 0, "", fontsize=10,
    ha="center", va="center",
    bbox=dict(boxstyle="round,pad=0.4", facecolor="white", alpha=0.8)
    )


    def init():
    point.set_data([], [])
    info_text.set_text("")
    return point, info_text


    def update(frame):
    t = frame * dt # time in hours
    theta = omega * t # angle in radians

    x = r * cos(theta) * scale
    y = r * sin(theta) * scale

    point.set_data([x], [y])
    info_text.set_text(
    f"Time: {t:.2f} hr\nRadius: {r:.1f} km\nSpeed: {speed:.2f} km/h"
    )
    return point, info_text



    # Create animation
    anim = FuncAnimation(
    fig, update, frames=frames, init_func=init, blit=True, interval=1000 / fps
    )


    with tqdm(total=frames, desc="Saving", unit="frame") as pbar:
    anim.save(filename, fps=fps, progress_callback=lambda i, n: pbar.update(1))

    # Add sound using MoviePy
    video = VideoFileClip(filename)
    video.audio = CompositeAudioClip([AudioFileClip("sound.wav")])
    video.write_videofile(filename)

    startfile(filename)


    Could you figure out what the culprit is and how to fix it?

    [​IMG]

    Edit


    Based on the given comment, I did the following but the problem still exists.

    # Add sound using MoviePy
    video = VideoFileClip(filename)
    audio = AudioFileClip("sound.wav")
    audio.duration = video.duration
    video.audio = CompositeAudioClip([audio])
    video.write_videofile(filename)

    Continue reading...

Compartilhe esta Página