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

Created on 6 Aug 2019  路  14Comments  路  Source: fluent-ffmpeg/node-fluent-ffmpeg

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 (c) 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!

Most helpful comment

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.

All 14 comments

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

You have to specify the input format, ffmpeg usually uses the file extension to automatically find the format

@njoyard I don't think it's the issue. I did try specifying the input format:

const input = fs.createReadStream(path.resolve("./debug-input.mp4"))
new FFMPEG(input)
    .inputFormat("mp4")
    .toFormat("mp4")
    .save(path.resolve("./debug.mp4"))

For the same Invalid data found when processing input

Also, this wouldn't explain why the output stream is also failing as I do specify a foFormat.

@Coriou did you end up solving this? I'm getting the same problem.

Nope, haven't looked back at it. I was thinking about what would be the best way to reproduce this directly with the ffmpeg binary (not using this node wrapper) but then got caught up in other things and never looked back at this issue since

I am also experiencing this very error with a readable stream coming from node-ftp. Filestreams work fine though.

@adrian-kriegel Could you show me a piece of code using filestreams that works for you please ?

@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.

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. 馃帀

@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.

Thanks @utkarsh914, didn't work though. This code returns the exact same error:

import fs from "fs"
import path from "path"
import ffmpeg from "fluent-ffmpeg"

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

new ffmpeg(input)
  .inputFormat("mp4")
  .outputOptions("-movflags frag_keyframe+empty_moov")
  .toFormat("mp4")
  .save(output)

Outputs

Error: ffmpeg exited with code 1: 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!

Even though I'd love for this issue to be resolved or - at least - understand what is wrong, it's a non-blocking issue for me as I just use Ffmpeg directly without any problems whatsoever.

Here the input file's probe:

ffprobe version 4.2.2 Copyright (c) 2007-2019 the FFmpeg developers
  built with Apple clang version 11.0.3 (clang-1103.0.32.59)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.2.2_5 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags=-fno-stack-check --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --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-libsoxr --enable-videotoolbox --disable-libjack --disable-indev=jack
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'test-input.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf58.29.100
  Duration: 00:04:05.03, start: 0.000000, bitrate: 2259 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1920x1080 [SAR 1:1 DAR 16:9], 2127 kb/s, 24 fps, 24 tbr, 12288 tbn, 48 tbc (default)
    Metadata:
      handler_name    : ISO Media file produced by Google Inc.
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 127 kb/s (default)
    Metadata:
      handler_name    : SoundHandler

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.

Thanks @FedericoCarboni, glad to know what the issue is !

i used this option and fixed
thanks @FedericoCarboni

.addOutputOption('-movflags','frag_keyframe+empty_moov')
Was this page helpful?
0 / 5 - 0 ratings

Related issues

mStirner picture mStirner  路  4Comments

bsonntag picture bsonntag  路  5Comments

jsamos picture jsamos  路  6Comments

baoxiangyang picture baoxiangyang  路  3Comments

geraldoramos picture geraldoramos  路  3Comments