node-fluent-ffmpeg: mp4 buffer as input fails to convert a video

Version information

  • fluent-ffmpeg version: 2.1.2
  • ffmpeg version: 4.1.3
  • OS: macos

Code to reproduce

A buffer comes from browser to node.js read by FileReader.

// videoArrayBuffer is a buffer coming from browser
let readableVideoBuffer = new stream.PassThrough();
    readableVideoBuffer.write(videoArrayBuffer);
    readableVideoBuffer.end()
ffmpeg()
      .input(readableVideoBuffer)
      .inputFormat("mp4")
      .outputOptions([
        "-pix_fmt yuv420p",
        "-movflags frag_keyframe+empty_moov",
        "-movflags +faststart"
      ])
      // .videoCodec("libx264")
      .toFormat("mp4")
      .save("test.mp4")

(note: if the problem only happens with some inputs, include a link to such an input file)

Expected results

expecting a properly saved video

Observed results

ffmpeg stderr: ffmpeg version 4.1.3 Copyright © 2000-2019 the FFmpeg developers built with Apple LLVM version 10.0.1 (clang-1001.0.46.4) configuration: --prefix=/usr/local/Cellar/ffmpeg/4.1.3_1 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags=‘-I/Library/Java/JavaVirtualMachines/adoptopenjdk-11.0.2.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/adoptopenjdk-11.0.2.jdk/Contents/Home/include/darwin’ --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libtesseract --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-videotoolbox --disable-libjack --disable-indev=jack --enable-libaom --enable-libsoxr libavutil 56. 22.100 / 56. 22.100 libavcodec 58. 35.100 / 58. 35.100 libavformat 58. 20.100 / 58. 20.100 libavdevice 58. 5.100 / 58. 5.100 libavfilter 7. 40.101 / 7. 40.101 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 libpostproc 55. 3.100 / 55. 3.100 [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9715001400] stream 0, offset 0x4f: partial file [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9715001400] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none, 1280x720, 10843 kb/s): unspecified pixel format Consider increasing the value for the ‘analyzeduration’ and ‘probesize’ options Input #0, mov,mp4,m4a,3gp,3g2,mj2, from ‘pipe:0’: Metadata: major_brand : mp42 minor_version : 0 compatible_brands: mp41isom creation_time : 2019-07-10T15:03:19.000000Z Duration: 00:00:02.13, start: 0.033333, bitrate: N/A Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none, 1280x720, 10843 kb/s, 30 fps, 30 tbr, 30k tbn, 60k tbc (default) Metadata: creation_time : 2019-07-10T15:03:19.000000Z handler_name : VideoHandler encoder : AVC Coding Stream mapping: Stream #0:0 -> #0:0 (h264 (native) -> h264 (libx264)) [mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f9715001400] stream 0, offset 0x4f: partial file pipe:0: Invalid data found when processing input Cannot determine format of input stream 0:0 after EOF Error marking filters as finished Conversion failed!

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 11
  • Comments: 34 (1 by maintainers)

Most upvoted comments

I know this is a bit late but, for future reference and for @Coriou This is a limitation of FFmpeg, specifically the MOV/MP4 muxer (switch to Matroska or WebM if you require streaming inputs), it requires output and input to be seekable.

There’s the output-only workaround described @utkarsh914, which uses the empty_moov flag. From the FFmpeg Docs:

[writes] an initial moov atom directly at the start of the file, without describing any samples in it.

This works for outputs, but for inputs, there’s no workaround I know about.

@Coriou you’ll need to add both .outputOptions('-movflags frag_keyframe+empty_moov') and .toFormat("mp4") in case you’re using output streams I don’t exactly know the reason behind it. But it is something like mp4 needs to write header in the beginning after completing whole encoding.

I have similar issues when using streams as inputs and / or outputs.

For example this works as you’d expect it to:

new ffmpeg(path.resolve("./debug-input.mp4"))
    .toFormat("mp4")
    .save(path.resolve("./debug.mp4"))

While this doesn’t:

const input = fs.createReadStream(path.resolve("./debug-input.mp4"))
const output = fs.createWriteStream(path.resolve("./debug.mp4"))

new ffmpeg(input)
    .toFormat("mp4")
    .pipe(output)

Using a stream as input yields ffmpeg exited with code 1: pipe:0: Invalid data found when processing input Cannot determine format of input stream 0:0 after EOF - I’ve tried other types of NodeJS readable / writable streams with the same results exactly.

Similarly, using an output stream also yields an error:

const output = fs.createWriteStream(path.resolve("./debug.mp4"))
new ffmpeg(path.resolve("./debug-input.mp4"))
    .toFormat("mp4")
    .pipe(output)

ffmpeg exited with code 1: Conversion failed! (I’m guessing it can’t write to the output stream)

I’m running ffmpeg 4.2.1 on MacOS and fluent-ffmpeg 2.1.2

i used this option and fixed thanks @FedericoCarboni

.addOutputOption('-movflags','frag_keyframe+empty_moov')

Everything is somewhat more complicated. The problem is that metadata in mp4 can be not only at the beginning of the file, but also at the end. And accordingly ffpmeg cannot get them. If you try on the client like this: ffmpeg -i input.mp4 -movflags faststart -acodec copy -vcodec copy output.mp4 And then send output file to the server, then everything will work. Hope it was helpful!

For people with input mp4 file issues: Something like this seems to work.

ffmpeg().input("<direct https link to mp4 file>")

No idea if FFMPEG will stream urls intelligently behind the scenes or if it downloads the entire video and then converts… But atleast it works 😃

It has been some time since I opened this issue, but I think I solved my issue by the following:

  1. Create a PassThrough stream to write your required bytes. const inputForFFMPEG = new stream.PassThrough()
  2. Pass it to the ffmpeg command and do whatever you want with it. I hope it helps:
ffmpeg(inputForFFMPEG).save('./directoryName/file.mp4').on('end', async () => {
          try {
           // Here I uploaded file to google cloud storage
          } catch (e) {
            // Here and below is an obsessive error checking
            console.log(e);
            throw e
          }
        }).on('error', (err) => {
          console.log(err)
        })
      } catch (e) {
        console.log(e)
        throw e
      }

Note: You can use google cloud to upload files through automatically generated upload link straight to storage and feed ffmpeg with that files URL.

Hope any of this helps to someone in the future. Good luck and happy coding. 🎉

For us, using paths referring to the video as input solved this issue.

Adding .addOutputOption('-movflags','frag_keyframe+empty_moov') didn’t solve the problem

I still have the same error:

Error: ffmpeg exited with code 1: pipe:0: Invalid data found when processing input
Cannot determine format of input stream 0:0 after EOF

Do you have any ideas ? Or other possible fixes ?

@Coriou I just tested it using a filestream as an output aswell as using one as the input. Using a filestream for the output does in fact not work for me. This works though: ffmpeg(fs.createReadStream('video.mp4')).inputFormat('mp4').[other commands] It seems to be the same code you posted. I am guessing that out mp4 files differ in some way.