What's the correct ffmpeg setting to prevent the video from 'lazy' loading the video's total duration?
I'm trying to transcode a video using ffmpeg (in NodeJS). When transcoding is finished ffmpeg uploads the video automatically to a bucket (GCP).
Hoverever, the video that ffmpeg produces doesn't have a clear total duration when played in a HTML video player. It's only after x (milli)seconds that the total video duration is known and displayed.
Using the fluent-ffmpeg NodeJS library:
const settings: VideoHDPresetSettings = {
format: "mp4",
codec: "libx264",
size: "1920x1080",
ratio: "16:9",
options: [
"-movflags", "frag_keyframe+empty_moov+faststart",
"-preset", "veryfast",
"-crf", "16",
],
};
ffmpeg({source: "input.mp4"})
.format(settings.format)
.videoCodec(settings.codec)
.size(settings.size)
.aspectRatio(settings.ratio)
.outputOptions(settings.options)
.writeToStream(outputStream);
This is fluent-ffmpeg's generated command:
ffmpeg -i input.mp4 -vcodec libx264 -filter:v scale=w=1920:h=1080 -f mp4 -movflags frag_keyframe+empty_moov+faststart -preset veryfast -crf 16 pipe:1
This is what I'd like it to be, when the video is loaded the total video duration is known immediatly.
https://storage.googleapis.com/uhasselt/problem/original (expired)
This is what the code above generates, when the video is loaded the total video duration is known yet. It's pretty difficult to detect with this video, so refresh a couple of times while looking at the video's total duration on the timeline.
https://storage.googleapis.com/uhasselt/problem/ffmpeg-result (expired)
What's the correct ffmpeg setting to prevent the video from 'lazy' loading the video's total duration? What am I doing wrong?
After some additional testing I found out that the .writeToStream(...)
is causing this behavior. This saving technique is used to directly stream the result to some url without having to save it on the machine's local disk.
I'm now using the .save("./output/path.mp4")
function to save ffmpeg's result on disk first, afterwards I stream it to my bucket (not included in code below).
I'm not sure why this works... I think it has something to do with ffmpeg now being able to jump back and change previous saved metadata, before delivering the final video (something that wasn't possible with the .writeToStream(...)
since the data stream is one continuous stream of data without the ability to jump back).
If you're using the CLI ffmpeg version instead of fluent-ffmpeg this change would correspond to not using the pipe:1
at the end of your ffmpeg command.
This is the final solution
// Exactly the same
const settings: VideoHDPresetSettings = {
format: "mp4",
codec: "libvpx-vp9",
size: "1920x1080",
ratio: "16:9",
options: [
"-movflags", "frag_keyframe+empty_moov+faststart",
"-preset", "veryfast",
"-crf", "30",
],
};
ffmpeg({source: "input.mp4"})
.format(settings.format)
.videoCodec(settings.codec)
.size(settings.size)
.aspectRatio(settings.ratio)
.outputOptions(settings.options)
.save("./output.mp4"); // NEW!