[Python] Video generation and ffmpeg and locally stored images

Discussão em 'Python' iniciado por Stack, Julho 3, 2025.

  1. Stack

    Stack Membro Participativo

    I am facing issue in ffmpeg while running the below code I'm working on a Flask application that generates a video by combining a sequence of images from a folder and a synthesized audio track using Bark (suno/bark-small). The idea is to use FFmpeg to stitch the images into a video, apply padding and scaling, and then merge it with the generated audio. I'm triggering the /generate-video endpoint with a simple curl POST request, passing a script that gets converted to audio. While the image and audio processing work as expected, FFmpeg fails during execution, and the server returns a 500 error. I've added error logging to capture FFmpeg’s stderr output, which suggests something is going wrong either with the generated input.txt file or the format of the inputs passed to FFmpeg. I'm not sure if the issue is related to file paths, the concat demuxer formatting, or possibly audio/video duration mismatch. Any insights on how to debug or correct the FFmpeg command would be appreciated.

    the curl request is

    curl -X POST http://localhost:5000/generate-video \
    -H "Content-Type: application/json" \
    -d '{"script": "Hello, this is a test script to generate a video."}' \
    --output output_video.mp4



    import os
    import uuid
    import subprocess
    from pathlib import Path
    import numpy as np
    from flask import Flask, request, jsonify, send_file
    from transformers import AutoProcessor, AutoModelForTextToWaveform
    from scipy.io.wavfile import write as write_wav
    import torch

    # ========== CONFIG ==========
    IMAGE_FOLDER = "./images"
    OUTPUT_FOLDER = "./output"
    RESOLUTION = (1280, 720)
    IMAGE_DURATION = 3 # seconds per image
    SAMPLE_RATE = 24000

    app = Flask(__name__)
    os.makedirs(OUTPUT_FOLDER, exist_ok=True)

    # Load Bark-small model and processor
    device = "cuda" if torch.cuda.is_available() else "cpu"
    processor = AutoProcessor.from_pretrained("suno/bark-small")
    model = AutoModelForTextToWaveform.from_pretrained("suno/bark-small").to(device)


    # ========== UTILS ==========
    def run_ffmpeg(cmd):
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if result.returncode != 0:
    print("[FFmpeg ERROR]\n", result.stderr.decode())
    raise RuntimeError("FFmpeg failed.")
    else:
    print("[FFmpeg] Success.")


    def find_images(folder):
    return sorted([
    f for f in Path(folder).glob("*")
    if f.suffix.lower() in {".jpg", ".jpeg", ".png"}
    ])


    def create_ffmpeg_input_list(images, list_file_path):
    with open(list_file_path, "w") as f:
    for img in images:
    f.write(f"file '{img.resolve()}'\n")
    f.write(f"duration {IMAGE_DURATION}\n")
    # Repeat last image to avoid cutoff
    f.write(f"file '{images[-1].resolve()}'\n")


    # ========== FLASK ROUTE ==========
    @app.route('/generate-video', methods=['POST'])
    def generate_video():
    data = request.get_json()
    script = data.get("script")
    if not script:
    return jsonify({"error": "No script provided"}), 400

    images = find_images(IMAGE_FOLDER)
    if not images:
    return jsonify({"error": "No images found in ./images"}), 400

    # Generate audio
    print("[1/3] Generating audio with Bark...")
    inputs = processor(script, return_tensors="pt").to(device)
    with torch.no_grad():
    audio_values = model.generate(**inputs)

    audio_np = audio_values[0].cpu().numpy().squeeze()
    audio_np = np.clip(audio_np, -1.0, 1.0)
    audio_int16 = (audio_np * 32767).astype(np.int16)

    audio_path = os.path.join(OUTPUT_FOLDER, f"{uuid.uuid4()}.wav")
    write_wav(audio_path, SAMPLE_RATE, audio_int16)

    # Create FFmpeg concat file
    print("[2/3] Preparing image list for FFmpeg...")
    list_file = os.path.join(OUTPUT_FOLDER, "input.txt")
    create_ffmpeg_input_list(images, list_file)

    # Final video path
    final_video_path = os.path.join(OUTPUT_FOLDER, f"{uuid.uuid4()}.mp4")

    # Run FFmpeg
    print("[3/3] Running FFmpeg to create video...")
    ffmpeg_cmd = [
    "ffmpeg", "-y",
    "-f", "concat", "-safe", "0", "-i", list_file,
    "-i", audio_path,
    "-vf", f"scale={RESOLUTION[0]}:{RESOLUTION[1]}:force_original_aspect_ratio=decrease,"
    f"pad={RESOLUTION[0]}:{RESOLUTION[1]}:(ow-iw)/2:(oh-ih)/2:color=black",
    "-c:v", "libx264", "-pix_fmt", "yuv420p",
    "-c:a", "aac", "-b:a", "192k",
    "-shortest", "-movflags", "+faststart",
    final_video_path
    ]

    try:
    run_ffmpeg(ffmpeg_cmd)
    except RuntimeError:
    return jsonify({"error": "FFmpeg failed. Check server logs."}), 500

    return send_file(final_video_path, as_attachment=True)


    # ========== RUN APP ==========
    if __name__ == '__main__':
    app.run(debug=True)

    Continue reading...

Compartilhe esta Página