Open GordoRank opened 8 years ago
This is terribly inefficient and I would like to avoid writing to disk.
Unfortunately there aren't many options here. Remember fluent-ffmpeg is just a wrapper library for the ffmpeg executable, so we have to work with what we have. Plus there is no reliable way of connecting both to stdin and stdout without risking deadlocks. So in the end you'll have to write either the input or the output to disk. This may be mitigated by writing to something that's likely to be a ramdisk (eg. /tmp).
If you really want performance, what you need is libav* bindings. I don't think those exist in nodejs.
I tried using streamifier and passing in the GIF
Buffer
in order to use a readableStream as the source but I ended up getting anEnd of File
Error.
Can you show your code, as well as the full ffmpeg output (as returned in the 'error' handler 2nd and 3rd args) ?
Thanks for the response njoyard. As requested here is the full console output:
Spawned Ffmpeg with command: ffmpeg -f gif -i pipe:0 -movflags faststart -pix_fmt yuv420p -vf scale=trunc(iw/2)*2:trunc(ih/2)*2 -f mp4 pipe:1
Stderr output: ffmpeg version N-80901-gfebc862 Copyright (c) 2000-2016 the FFmpeg developers
Stderr output: built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
Stderr output: configuration: --extra-libs=-ldl --prefix=/opt/ffmpeg --mandir=/usr/share/man --enable-avresample --disable-debug --enable-nonfree --enable-gpl --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --disable-decoder=amrnb --disable-decoder=amrwb --enable-libpulse --enable-libfreetype --enable-gnutls --enable-libx264 --enable-libx265 --enable-libfdk-aac --enable-libvorbis --enable-libmp3lame --enable-libopus --enable-libvpx --enable-libspeex --enable-libass --enable-avisynth --enable-libsoxr --enable-libxvid --enable-libvidstab
Stderr output: libavutil 55. 28.100 / 55. 28.100
Stderr output: libavcodec 57. 48.101 / 57. 48.101
Stderr output: libavformat 57. 41.100 / 57. 41.100
Stderr output: libavdevice 57. 0.102 / 57. 0.102
Stderr output: libavfilter 6. 47.100 / 6. 47.100
Stderr output: libavresample 3. 0. 0 / 3. 0. 0
Stderr output: libswscale 4. 1.100 / 4. 1.100
Stderr output: libswresample 2. 1.100 / 2. 1.100
Stderr output: libpostproc 54. 0.100 / 54. 0.100
Stderr output: pipe:0: End of file
Stderr output:
Cannot process video: ffmpeg exited with code 1: pipe:0: End of file
[Error: ffmpeg exited with code 1: pipe:0: End of file]
And here is the example code I am using to test this. For now I have not hooked up the output stream to create a new Buffer, but my understanding is that this should still work.
var inStream = streamifier.createReadStream(gifBuffer);
var command = ffmpeg(inStream)
.inputFormat('gif')
.outputOptions([
'-movflags faststart',
'-pix_fmt yuv420p',
'-vf scale=trunc(iw/2)*2:trunc(ih/2)*2'
])
.toFormat('mp4')
.on('start', function(commandLine) {
console.log('Spawned Ffmpeg with command: ' + commandLine);
})
.on('stderr', function(stderrLine) {
console.log('Stderr output: ' + stderrLine);
})
.on('error', function(err, stdout, stderr) {
console.log('Cannot process video: ' + err.message);
console.log(stdout);
console.log(stderr);
})
.on('progress', function(progress) {
console.log('Processing: ' + progress.percent + '% done');
})
.on('end', function() {
console.log('Finished processing');
});
var ffstream = command.pipe();
ffstream.on('data', function(chunk) {
console.log('ffmpeg just wrote ' + chunk.length + ' bytes');
});
Have you tried commenting out the event:
.on('progress', function(progress) {
console.log('Processing: ' + progress.percent + '% done');
})
I use fluent-ffmpeg to do similar: Chrome with WebRTC (webM/opus codec) -> Express (string base64) -> stream -> fluent-ffmpeg WebM to OGG -> stream -> IBM Watson speech to text -> res.send() Subscribing to 'progress' and having the console.log() in the event interferes with the input pipe.
If you receive the gif file through a request in base64, I would also try to replace usage of streamifier:
var inStream = streamifier.createReadStream(gifBuffer);
by
var stream = new stream.Readable();
stream.push(data, 'base64');
stream.push(null);
@GordoRank You can avoid writing the GIF to disk by inputting it as a readable stream, but you will have to write the MP4 to disk. The reason is that the MP4 muxer requires a seekable output, as it jumps around while writing the output, as opposed to only appending it. That means ffmpeg
can't stream the MP4 back to node-fluent-ffmpeg, as standard output isn't seekable, and that's the only mechanism available to return output as a stream.
As hinted at by @njoyard, a direct node-libav binding would work because a Buffer would be a seekable output, but there's no way to accomplish that with a library that wraps the ffmpeg program.
I am trying to use ffmpeg with GIFs as input and MP4s as output. Looks like there is no support for gif_pipe and mp4_pipe. I am using shell from Java. ffmpeg -formats lists all the supported format Is gif_pipe and mp4_pipe going to be supported in future?
Any new developments? I have almost the same issue - the only difference is that I want to do a slideshow from my mp4 video.
When I'm using ffmpeg with buffer as input the output video is incomplete:
let inStream = streamifier.createReadStream(file.Body);
ffmpeg(inStream).inputFormat('gif')
.outputOptions(['-pix_fmt yuv420p', '-movflags frag_keyframe+empty_moov', '-movflags +faststart'])
.toFormat('mp4').save('test.mp4')
.on('error', function(err, stdout, stderr) {
console.log('Cannot process video: ' + err.message);
})
.on('end', function() {
console.log('Finished processing');
});
but if i use the same input file as file the video is ok, some help to find the problem?
When specifing the input format as "gif_pipe", it worked for me but I'm getting 0 seconds videos for some gifs. When I give filepath, it is working well but I cannot make it work for gif streams.
Even I am facing the same issue. Giving input format as gif_type gives 1-sec videos
I am trying to convert animated GIF's to MP4 videos, on the fly, as the user requests them, after resizing/processing the GIF's first as requested.
After all processing on the GIF is complete I have its contents stored in a
Buffer
, and I need to finally output the resulting MP4 as aBuffer
also.Currently, I have to write the
Buffer
to a temporary file, perform the conversion, then read the converted file into aBuffer
and finally pass it into thecallback
.This is terribly inefficient and I would like to avoid writing to disk. How can I simply convert the
GIF
buffer into anMP4
buffer?I tried using streamifier and passing in the GIF
Buffer
in order to use a readableStream as the source but I ended up getting anEnd of File
Error.Here is a stripped down version of the current method I am using which involves writing the files to disk before processing:
Any help would be greatly appreciated.