Ilan Yashuk
Ilan Yashuk

Reputation: 259

Using 'blend' filter with ffmpeg colors my video pink

I am using ffmpeg's library fluent-ffmpeg in nodejs.

My purpose is to blend a black box with text upon a video (using 'lighten' blend filter) so the background will be deleted in a clean & beautiful way.

For some reason the video turns pink after I do that.

The code for blending:

return new Promise((resolve, reject) => {
ffmpeg()
  .input(videoPath) // input '0', the background video
  .input(picturePath) // input '1', the black box with text
  .complexFilter([
    {
      filter: "blend",
      inputs: ["1", "0"],
      options: {
        all_mode: "lighten",
      },
    },
  ])

  .saveToFile(endPath)
  .on("error", (err) => {
    console.log(err);
    reject(false);
  })
  .on("end", () => {
    resolve(true);
  });

Before the blend:

Both video and picture before the blend

After the blend: The resulted (undesired) video

I've read here that the problem's cause may be that blend's format is YUV and not GBRP. I've tried it and it didn't work.

Any help would be appreciated. If possible, please give a code answer and not a command-line answer because converting it sometimes tends to do problems.

Upvotes: 0

Views: 1053

Answers (2)

Ilan Yashuk
Ilan Yashuk

Reputation: 259

I've figured it out. I couldn't find a complete answer in the web I'll post one here in case anyone gets stuck here.

The problem's cause

Video format .mp4 as written here gets encoded in YUV, which is not the way we are used to, with RGB pixels. Because of that, lighten blend don't work as I thought it would.

Solution

  1. Convert the video to gbrp format
  2. Blend video with another video/image
  3. Convert it back to yuv420p format (because most players can't read videos encoded in format gbrp)

CLI:

 .\ffmpeg.exe -i "generated\vids\vid.mp4" -i ".\generated\imgs\img.png" -filter_complex "[0]format=gbrp[vid];[1][vid]blend=all_mode=lighten[final];[final]format=yuv420p" test-video.mp4

Code (Javascript, via fluent-ffmpeg):

ffmpeg()
  .input(videoPath) // input '0'
  .input(imagePath) // input '1'
  .complexFilter(
    [
      { // Convert video to 'gbrp' format
        filter: 'format',
        inputs: ['0'],
        options: 'gbrp',
        outputs: 'vid'
      },
      { // Blend image on top of video
        filter: "blend",
        inputs: ["1", "vid"],
        options: {
          all_mode: "lighten",
        },
        outputs: 'final_video'
      },
      { // Convert video back to yuv420p format
        filter: 'format',
        inputs: ['final_video'],
        options: 'yuv420p',
      },

    ]
  )

Upvotes: 1

kesh
kesh

Reputation: 5463

You need to figure out how to turn this into fluent-ffmpeg, but consider using the colorkey filter with the overlay filter. Something along the line of:

[1:v]colorkey=black[text];[0:v][text]overlay=x=(main_w-overlay_w)/2:y=(main_h-overlay_h)/2

The colorkey filter turns the specified color transparent, so you can place its output right on the main video to get your desired effect. See the links above for other options.

Upvotes: 0

Related Questions