Newest 'ffmpeg' Questions - Stack Overflow

http://stackoverflow.com/questions/tagged/ffmpeg

Les articles publiés sur le site

  • Write EPIPE after upgrade Node.js

    30 juillet, par Rougher

    I am using this code for detecting audio replay gain. It was working well with Node.js 16, but after upgrading to Node.js 22, it started crashing a few times in an hour with this error:

    write EPIPE
        at WriteWrap.onWriteComplete [as oncomplete] (node:internal/stream_base_commons:87:19) {
      errno: -32,
      code: 'EPIPE',
      syscall: 'write'
    }
    

    My original code was

    static getReplayGainVolume(audioData: Buffer) {
            // Calculate the mean volume of the audio file at the given filePath
            var ffmpeg = spawn('ffmpeg', [
                '-i', '-',
                '-af', 'replaygain',
                '-f', 'null', '/dev/null',
                '-hide_banner', '-nostats'
            ]);
    
            var output = '';
    
            ffmpeg.stdin.write(audioData);
            ffmpeg.stdin.end();
    
            return new Promise((resolve,reject)=>{
                ffmpeg.on('error', function (err: any) {
                    reject(err);
                });
                
                ffmpeg.on('close', function (_code: any) {
                    // [Parsed_replaygain_0 @ 0000000002a2b5c0] track_gain = +6.53 dB
                    if (!output.includes("track_gain")) {
                        reject(output);
    
                        return;
                    }
    
                    const gainWithDb = output.split("track_gain = ")[1];
                    if (!gainWithDb) {
                        reject(output);
    
                        return;
                    }
    
                    const gain = gainWithDb.split(" dB")[0];
                    if (!gain) {
                        reject(output);
    
                        return;
                    }
    
                    resolve(parseFloat(gain));
                });
                
                ffmpeg.stderr.on('data', function (data: any) {
                    // ffmpeg sends all output to stderr. It is not a bug, it is a feature :)
                    var tData = data.toString('utf8');
                    output += tData;
                });
            });
        }
    

    Then after search in forums and Google, I improved (I hope I improved it with cleanups)

    static getReplayGainVolume(audioData: Buffer): Promise {
            return new Promise((resolve, reject) => {
                const FFMPEG_PATH = 'ffmpeg'; // Adjust this if ffmpeg is not in system PATH
                const FFMPEG_TIMEOUT_MS = 30 * 1000; // 30 seconds timeout for FFmpeg execution
    
                let ffmpeg: ChildProcessWithoutNullStreams;
                let output = ''; // Accumulate all stderr output
    
                // Timeout for the FFmpeg process itself
                const ffmpegTimeout = setTimeout(() => {
                    log.error(`[FFmpeg] FFmpeg process timed out after ${FFMPEG_TIMEOUT_MS / 1000} seconds. Killing process.`);
                    if (ffmpeg && !ffmpeg.killed) {
                        ffmpeg.kill('SIGKILL'); // Force kill
                        reject(new Error(`FFmpeg process timed out and was killed.`));
                    }
                }, FFMPEG_TIMEOUT_MS);
    
                // --- Define cleanup function to be called on process exit/error ---
                const cleanup = (shouldReject = false, error?: Error | string) => {
                    clearTimeout(ffmpegTimeout); // Ensure timeout is cleared
    
                    // Remove all listeners to prevent leaks
                    // This is CRITICAL for long-running bots that spawn many child processes
                    ffmpeg.stdin.removeAllListeners();
                    ffmpeg.stdout.removeAllListeners();
                    ffmpeg.stderr.removeAllListeners();
                    ffmpeg.removeAllListeners(); // Remove process listeners
    
                    if (ffmpeg && !ffmpeg.killed) { // Ensure ffmpeg process is killed if still alive
                        ffmpeg.kill(); // Graceful kill (SIGTERM), then wait for exit. If not, then SIGKILL.
                    }
    
                    if (shouldReject) {
                        reject(error instanceof Error ? error : new Error(String(error)));
                    }
                };
    
                try {
                    ffmpeg = spawn(FFMPEG_PATH, [
                        '-i', 'pipe:0', // Read input from stdin (pipe:0)
                        '-af', 'replaygain',
                        '-f', 'null', '/dev/null', // Write output to null device (discard audio output)
                        '-hide_banner', '-nostats' // Suppress ffmpeg's initial info and progress stats
                    ], { stdio: ['pipe', 'pipe', 'pipe'] }); // Explicitly pipe stdin, stdout, stderr
    
                    // --- CRITICAL: Event Handlers for ffmpeg process ---
    
                    // 1. Handle errors during spawning or execution (e.g., ffmpeg not found)
                    ffmpeg.on('error', (err: any) => {
                        log.error(`[FFmpeg] Failed to spawn or execute FFmpeg process:`, err);
                        cleanup(true, new Error(`FFmpeg process error: ${err.message}`));
                    });
    
                    // 2. Accumulate stderr output (where replaygain results and ffmpeg errors are printed)
                    ffmpeg.stderr.on('data', (data: Buffer) => {
                        output += data.toString('utf8');
                    });
    
                    // 3. Handle process exit (success or failure)
                    ffmpeg.on('close', (code: number) => { // 'close' indicates process has exited
                        log.debug(`[FFmpeg] FFmpeg process exited with code: ${code}.`);
                        if (code !== 0) { // Non-zero exit code means failure
                            log.error(`[FFmpeg] FFmpeg process exited with non-zero code ${code}. Output:\n${output}`);
                            cleanup(true, new Error(`FFmpeg process failed with exit code ${code}. Output: ${output}`));
                            return;
                        }
    
                        // If successful exit (code 0), parse the output
                        if (!output.includes("track_gain")) {
                            log.error(`[FFmpeg] 'track_gain' not found in FFmpeg output (exit code 0). Output:\n${output}`);
                            cleanup(true, new Error(`'track_gain' not found in FFmpeg output. Output: ${output}`));
                            return;
                        }
    
                        try {
                            // Regex to parse track_gain (e.g., "+6.53 dB" or "-12.00 dB")
                            const gainMatch = output.match(/track_gain\s*=\s*([+-]?\d+\.?\d*)\s*dB/);
                            if (gainMatch && gainMatch[1]) {
                                const gain = parseFloat(gainMatch[1]);
                                log.debug(`[FFmpeg] Replay gain volume: ${gain} dB.`);
                                cleanup(); // Clean up on success
                                resolve(gain);
                            } else {
                                log.error(`[FFmpeg] Failed to parse gain from FFmpeg output. Output:\n${output}`);
                                cleanup(true, new Error(`Failed to parse gain from FFmpeg output. Output: ${output}`));
                            }
                        } catch (parseError: any) {
                            log.error(`[FFmpeg] Error parsing FFmpeg replay gain output:`, parseError);
                            cleanup(true, new Error(`Error parsing FFmpeg output: ${parseError.message}. Output: ${output}`));
                        }
                    });
    
                    // 4. Write audio data to ffmpeg's stdin
                    // This is the only write operation that could throw EPIPE in this function.
                    try {
                        ffmpeg.stdin.write(audioData);
                        ffmpeg.stdin.end(); // Close stdin to signal end of input
                    } catch (stdinError: any) {
                        log.error(`[FFmpeg] Error writing audioData to FFmpeg stdin:`, stdinError);
                        // This error means ffmpeg's stdin pipe closed unexpectedly.
                        // This is the direct equivalent of an EPIPE (Broken Pipe) at the child process level.
                        cleanup(true, new Error(`Failed to pipe audio data to FFmpeg stdin: ${stdinError.message}`));
                    }
    
                } catch (spawnError: any) { // Catch errors from the spawn call itself (e.g., FFMPEG_PATH is invalid)
                    log.error(`[FFmpeg] Error spawning FFmpeg:`, spawnError);
                    cleanup(true, new Error(`Failed to spawn FFmpeg process: ${spawnError.message}`));
                }
            });
        }
    

    But unfortunately I still get the same error. Has anyone encountered this problem? How can I solve it?

    I use ffmpeg version 4.2.7-0ubuntu0.1

  • How can I decode MegaRace (93/94) .HNM videos ? — FFmpeg fails and legacy tools are missing [closed]

    29 juillet, par L P

    Goal

    • I want to convert the original full‑motion videos shipped with MegaRace (DOS, 1993/94) from Cryo’s proprietary HNM format into a modern, playable container (e.g. lossless AVI/PNG sequence).
    • Capturing the screen while the game runs is not an option: the target is the pure background animation (no sprites, no overlays, no DOSBox scaling filters, no subtitles).

    What I already have

    • Extracted all *.HNM files out of MEGARACE.DAT with Game Extractor.
      (Directory listing: 100+ files from AZUR.HNM to VWBT5.HNM.)
    • Verified that they are indeed Cryo HNM: the wiki pages [1] and [2] say MegaRace uses an early variant (v1/v2) written by Pascal Urro (might also used in 92's Dune, 95's Lost Eden etc.).
    • Tried FFmpeg (from latest to earliest) with ffplay -f hnm -i EXPLO.HNM, but every file aborts with invalid resolution and invalid data found when processing input. Same for ffprobe and ffmpeg -i.
    • Searched for legacy tools:
      • hnmdec / hnm2avi — no longer included in modern ScummVM‑Tools; seems to have been present at some point.
      • extract_cryo — source vanished.
      • Game Media Formats DirectShow Filters, by Valery Anisimovsky could, in theory, load the vendor codecs (CM6_*.dll) and expose them to DirectShow, but I haven't found the necessary Cryo DLLs shipped with MegaRace.
    • Looked at the DOSBox “Video Codec” folder – it only contains ZMBV (zmbv.dll, zmbv.inf), which is unrelated (that’s the codec DOSBox uses for screen‑capture).

    Environment

    • macOS Sequoia 15.5 on Apple Silicon (but I can boot Windows 11 ARM or use x86_64 VMs if the solution requires them).
    • No need for audio; video stream alone is fine.

    Why this matters

    • Archiving early FMV assets is part of game preservation. MegaRace’s CG backgrounds are unique and currently inaccessible without running the whole DOS game.

    What I’m looking for

    • Specifications or source code for the HNM v1/v2 codec.
    • A working decoder (CLI or library) for any platform so I can batch‑convert all files.
    • Pointers on how to patch FFmpeg’s current libavcodec/hnm4video.c to support the older variant.
    • Alternatively, hints on extracting the player’s built‑in decoder from MEGARACE.EXE (or ScummVM’s internal implementation, if any) and wrapping it.
    • Any lead, paper, or old DOS utility is appreciated!
  • How to compile latest FFmpeg Library for Android ?

    29 juillet, par Timo Schuck

    Struggling to put together a working and generally best practice build of current FFmpeg. There seems to be no up-to-date documents or tutorials. What does exist is full of outdated links or build-scripts that do not work.

  • Input path errors while running FFMPEG and keeping subdirectory structure [closed]

    29 juillet, par piet koos

    My goal is to reduce the size of all .ogg files found under the parent directory "Formatted", while keeping the sub-directories and files structure the same.

    Example

    .../Formatted/"test1, test2, test3 and so on"/"files.ogg"
    

    to

    .../Contributors/"test1, test2, test3 and so on"/"reduced_files.ogg"
    

    However. While the script runs ffmpeg it seems that the some input file paths gives "Error opening input: No such file or directory". eg. It either cuts off the 'h' of home or adds a '.' to the end of the file extension.

    "ome/user1/Downloads/Encoding/Formatted/test1/"file""
    

    or

    Parse error, at least 3 arguments were expected, only 1 given in string "oding/Formatted/test1/"file"
    

    Resulting in

    .../Contributors/"test1, test2, test3 and so on"/ with only a single file or missing .ogg files.
    

    I'm new to coding, any help is appreciated . I've tried echoing the variables to make sure they are correct but early on in the process echo "3" "$dirName" shows the absolute path being inrorrect.

    #!/bin/bash
    
    sourceDir=$HOME/Downloads/Encoding/Formatted
    destDir=$HOME/Backup/LEARN/Contributors
    
    find ~/Downloads/Encoding/Formatted/ -type f -name "*.ogg" | while IFS= read -r d; do
    #    find -name "*.ogg" 
        echo "1" "$d"
    baseName=$(basename "$d")
        echo "2" "$baseName"
    dirName=$(dirname "$d")
        echo "3" "$dirName"
    dirName_0=$(basename "$dirName")
        echo "4" "$dirName_0"
        echo "5" "$destDir"
    outputDir="$destDir/$dirName_0"
        echo "6" "$outputDir"
    outputPath="$outputDir/$baseName"
       
    #    echo "1" "$d"
    #    echo "2" "$baseName"
        echo "3" "$dirName"
    #    echo "4" "$dirName_0"
    #    echo "5" "$destDirecho"
    #    echo "6" "$outputDir"
    #    echo "7" "$outputPath"
    #    echo "8" "$destDir/$dirName_0/$baseName"
    #    echo "9" "$sourceDir"
    
        mkdir -p "$outputDir"
    
        ffmpeg -i "$d" -b:a 24k -acodec libopus -map_metadata 0 -map_metadata 0:s:0 "$outputPath"
     
    done
    
    For the first file found, *echo* returns:
    
    1 /home/user/Downloads/Encoding/Formatted/test/file1.ogg
    2 file1.ogg
    3 /home/user/Downloads/Encoding/Formatted/test
    4 test
    5 /home/user/Backup/LEARN/Contributors
    6 /home/user/Backup/LEARN/Contributors/test
    7 /home/user/Backup/LEARN/Contributors/test/file1.ogg
    8 /home/user/Backup/LEARN/Contributors/test/file1.ogg
    9 /home/user/Downloads/Encoding/Formatted
    
    Which is correct, but then for the next file found:
    
    1 ome/user/Downloads/Encoding/Formatted/test/file2.ogg
    2 file2.ogg
    3 ome/user/Downloads/Encoding/Formatted/test
    4 test
    5 /home/user/Backup/LEARN/Contributors
    6 /home/user/Backup/LEARN/Contributors/test
    7 /home/user/Backup/LEARN/Contributors/test/file2.ogg
    8 /home/user/Backup/LEARN/Contributors/test/file2.ogg
    9 /home/user/Downloads/Encoding/Formatted
    
    line 1 and 3 both miss a h from home? It does this for files in multiple folders.
    
  • how to combine several video random any one to create 1 new video ? using ffmpeg ? [closed]

    28 juillet, par Sky Moon

    how to combine several video random any one to create 1 new video? for example, I have 10 videos: 01.mp4; 02.mp4 ... 10.mp4 I want to combine random 5 of them to create 1 video example: (01.mp4+ 03.mp4+ 04.mp4+ 06.mp4 + 08.mp4) = 1 new video

    (02.mp4+ 04.mp4+ 05.mp4+ 06.mp4 + 09.mp4) = 1 new video

    Similar: random combination of 50 videos of 1000 videos to create 1 new video?