fluent-ffmpeg / node-fluent-ffmpeg

A fluent API to FFMPEG (http://www.ffmpeg.org)
MIT License
7.62k stars 872 forks source link

Error: Output format mp4 is not available #1262

Open alpacaPwaa opened 2 months ago

alpacaPwaa commented 2 months ago

Version information

Code to reproduce

createVideo: privateProcedure
    .input(
      z.object({
        fileId: z.string(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { getUser } = getKindeServerSession();
      const user = await getUser();

      if (!user || !user.id || !user.email) {
        throw new TRPCError({ code: "UNAUTHORIZED" });
      }

      const dbUser = await db.user.findFirst({
        where: {
          id: user.id,
        },
      });

      if (!dbUser) {
        throw new TRPCError({
          code: "UNAUTHORIZED",
          message: "User not found in the database.",
        });
      }

      const putObjectCommand = new PutObjectCommand({
        Bucket: process.env.AWS_BUCKET_NAME!,
        Key: generateFileName(),
      });

      const s3 = new S3Client({
        region: process.env.AWS_BUCKET_REGION!,
        credentials: {
          accessKeyId: process.env.AWS_ACCESS_KEY!,
          secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
        },
      });

      const signedURL = await getSignedUrl(s3, putObjectCommand, {
        expiresIn: 60,
      });

      const ffmpeg = require("fluent-ffmpeg");
      const passthroughStream = new PassThrough();

      ffmpeg({ source: "./template1.mp4" })
        .on("end", async () => {
          console.log("Job done");
          await uploadToS3(passthroughStream);
        })
        .on("error", (error: string) => {
          console.error("Error:", error);
        })
        .videoFilter({
          filter: "drawtext",
          options: {
            text: "hi",
            fontsize: 100,
            fontcolor: "white",
            x: "(w-text_w)/2",
            y: "(h-text_h)/2",
            box: 1,
            boxcolor: "black@0.5",
            boxborderw: 5,
            fontfile: "/Windows/fonts/calibri.ttf",
          },
        })
        .noAudio()
        .addOutputOption("-f", "mp4")
        .videoCodec("libx264")
        .outputFormat("mp4")
        .outputOptions(["-movflags frag_keyframe+empty_moov"])
        .pipe(passthroughStream, { end: true });

      const uploadToS3 = async (stream: PassThrough) => {
        const upload = new Upload({
          client: s3,
          params: {
            Bucket: process.env.AWS_BUCKET_NAME!,
            Key: generateFileName(),
            Body: stream,
          },
        });
        await upload.done();
      };

      const createdVideo = await db.video.create({
        data: {
          name: "Test Name",
          url: signedURL.split("?")[0],
          key: signedURL,
          fileId: input.fileId,
        },
      });

      return createdVideo;
    }),

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

Expected results

I should be able to save the video to s3

Observed results

Error: Output format mp4 is not available at eval (webpack-internal:///(rsc)/./node_modules/fluent-ffmpeg/lib/capabilities.js:589:21) at nextTask (webpack-internal:///(rsc)/./node_modules/async/dist/async.mjs:5892:9) at next (webpack-internal:///(rsc)/./node_modules/async/dist/async.mjs:5900:9) at eval (webpack-internal:///(rsc)/./node_modules/async/dist/async.mjs:430:16) at eval (webpack-internal:///(rsc)/./node_modules/fluent-ffmpeg/lib/capabilities.js:549:7) at handleExit (webpack-internal:///(rsc)/./node_modules/fluent-ffmpeg/lib/processor.js:170:11) at ChildProcess.eval (webpack-internal:///(rsc)/./node_modules/fluent-ffmpeg/lib/processor.js:184:11) at ChildProcess.emit (node:events:518:28) at ChildProcess._handle.onexit (node:internal/child_process:294:12) at Process.callbackTrampoline (node:internal/async_hooks:130:17)

Prameelagolusula commented 2 months ago

same issue with me

benharp commented 2 months ago

I have a similar issue (although all the formats seem broken for me) Recently upgraded my ffmpeg version. Looks like newer versions of ffmpeg -formats have added a new info column for devices, which adds a space between the mux/demux columns and the format name:

New (build from March 2024):

Formats:
 D.. = Demuxing supported
 .E. = Muxing supported
 ..d = Is a device
 ---
  E  mp4             MP4 (MPEG-4 Part 14)

Old (build from June 2023):

File formats:
 D. = Demuxing supported
 .E = Muxing supported
 --
  E mp4             MP4 (MPEG-4 Part 14)

(Obviously, mp4 is just an example, I'm not going to paste the whole format list here.)

My guess at what is happening: The regex that Fluent-FFmpeg uses to read FFmpeg's format list and determine its format support doesn't know how to read the extra space, so Fluent thinks there aren't any valid formats. Regex is here: https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/blob/4e02d12573052c00ac4becee17e40580e855d308/lib/capabilities.js#L18

Then, when you try to run a command, the error checking at line 589 compares its (empty) list of valid formats to your format, determines it can't support the format, and throws the error.

alpacaPwaa commented 2 months ago

@benharp I try running ffmpeg -format and I also had the same column for devices. Does this mean I have to downgrade my ffmpeg version? What version works for you?

Formats:
 D.. = Demuxing supported
 .E. = Muxing supported
 ..d = Is a device
 ---
alpacaPwaa commented 2 months ago

@benharp followed your comment and downgraded my ffmpeg to ffmpeg version 6.1-full now it can finish the stream. Thanks your hint helps a lot!

vimtor commented 2 months ago

@alpacaPwaa should this issue be closed? I mean, you can fix it by downgrading the version, but now Homebrew installs version 7 by default so maybe this should be taken into account now.

MarianoFacundoArch commented 2 months ago

We should fix the regexpr and make a new fluent-ffmpeg version? Is that possible? Any maintainer?

alpacaPwaa commented 2 months ago

It seems like I have to re-open the issue, everyone here's right although there's a workaround for this issue it's still better to address the root cause.

DoomsdayDevice commented 2 months ago

Use patch-package until it gets fixed. This worked in my case:

diff --git a/node_modules/fluent-ffmpeg/lib/capabilities.js b/node_modules/fluent-ffmpeg/lib/capabilities.js
index 3722ff1..3434210 100644
--- a/node_modules/fluent-ffmpeg/lib/capabilities.js
+++ b/node_modules/fluent-ffmpeg/lib/capabilities.js
@@ -15,7 +15,7 @@ var ffCodecRegexp = /^\s*([D\.])([E\.])([VAS])([I\.])([L\.])([S\.]) ([^ ]+) +(.*
 var ffEncodersRegexp = /\(encoders:([^\)]+)\)/;
 var ffDecodersRegexp = /\(decoders:([^\)]+)\)/;
 var encodersRegexp = /^\s*([VAS\.])([F\.])([S\.])([X\.])([B\.])([D\.]) ([^ ]+) +(.*)$/;
-var formatRegexp = /^\s*([D ])([E ]) ([^ ]+) +(.*)$/;
+var formatRegexp = /^\s*([D ])([E ])([d ]) ([^ ]+) +(.*)$/;
 var lineBreakRegexp = /\r\n|\r|\n/;
 var filterRegexp = /^(?: [T\.][S\.][C\.] )?([^ ]+) +(AA?|VV?|\|)->(AA?|VV?|\|) +(.*)$/;

@@ -527,7 +527,7 @@ module.exports = function(proto) {
       lines.forEach(function(line) {
         var match = line.match(formatRegexp);
         if (match) {
-          match[3].split(',').forEach(function(format) {
+          match[4].split(',').forEach(function(format) {
             if (!(format in data)) {
               data[format] = {
                 description: match[4],
MarianoFacundoArch commented 2 months ago

Fixed here https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/issues/1266

You can also install package from: https://www.npmjs.com/package/fluent-ffmpeg-7 and just change the import to from 'fluent-ffmpeg-7'

I did a quick version there till official version gets fixed.

Azarattum commented 2 months ago

Is there a way to skip format checks? I want my code to work on both version of ffmpeg

MarianoFacundoArch commented 2 months ago

You can use my code, it works on both versions!

MarianoFacundoArch commented 2 months ago

You can directly install from the npm with npm i fluent-ffmpeg-7. I called like that just to reinforce that it also works on FFmpeg 7

totallytavi commented 1 month ago

@njoyard Old issue

vimtor commented 1 month ago

This has been fixed in https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/issues/1266