1. Introduction to streaming processing
Let’s start with an example:
ffmpeg -s 0 -i input.mp4 -t 10 output.mp4
Copy the code
This command will intercept the input video input.mp4 from 0 to 10 seconds and save the output.mp4 file. Commands can be divided into three parts:
- File location
- Network location, used to implement network push flow
-
To output the command result as a standard output stream
With the – feature, we can call ffmpeg commands in pipe style, for example:
ffmpeg -s 0 -i input.mp4 -t 10 -f mpegts - | tee output.ts
Copy the code
Tip:
When – is used, FFMPEG will try to follow the pipe communication constraints and output the video stream after command processing to the standard output stream; Output the command execution process information to the standard error stream.
2. Use it in node
The biggest benefit of streaming is that you can retrieve a portion of the data without waiting for the entire video command to be processed. This can improve the response speed in performance-sensitive scenarios such as Web video services, live streaming, etc. This is explained in more detail in my other blog post “IMPLEMENTING dynamic bitstream Video Services with HLS + FFMPEG”. In the node implementation, ffmpeg command is called by the Spawn interface, and the standard output stream of ffMpeg command is output to the target video file by means of the pipeline communication mechanism between the parent and child processes.
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
function transform(sourceFile, outputStream, start, duration) {
const params = [`-ss`, start, `-i`, sourceFile, `-t`, duration, '-f'.'mpegts'.The '-'];
return new Promise((r, j) = > {
const cp = spawn('ffmpeg', params);
// ffmpeg standard output
cp.stdout.pipe(outputStream);
// Outputs procedure logs executed by FFmPEG to the program's standard output stream, usually console
cp.stderr.pipe(process.stdout);
cp.on('error', (err) => {
j(err);
});
cp.on('close', (code) => {
console.log(`ffmpeg process close all stdio with code ${code}`);
r(code);
});
cp.on('exit', (code) => {
console.log(`ffmpeg process exited with code ${code}`);
});
});
}
async function run() {
const inputFile = path.join(__dirname, 'test.mp4');
const output = fs.createWriteStream(path.join(__dirname, 'output.mp4'));
await transform(inputFile, output, 0.100);
}
run();
Copy the code
Operation effect:
3. Pay attention to the point
Although FFMPEG provides streaming output, it is not suitable for all scenarios. I briefly tested it and found:
- When the output encapsulation format is
mp4
When an errormuxer does not support non seekable output
, the exception is becausemp4
Instead of writing sequentially, you need to do seek multiple times to insert the data into the appropriate place when writing different types of boxes, somp4
The format requires that the output stream beseekable
Stdout will blind you. - When the output encapsulation format is
hls
When warningCannot use rename on non file protocol, this may lead to races and temporary partial files
This is because HLS needs to output multiple files, includingm3u8
And a pile ofts
, by defaultts
Shards are named according to the shard sequence, so using a standard output stream that cannot be renamed is a mistake.