Arco Voltaico
Arco Voltaico

Reputation: 814

FFmpeg is Not Working on my Electron Angular app

This previously working FFMPEG implementation, is no longer successful on my updated Angular 14 Electron 19 project. The getAudiVolume will exit with this error: " An error occurred while analysing: Output format null is not available"

IMPLEMENTING NORMALISATION

The component method

downloadYoutube(id: string){
  const filename = id+'.mp4';
  const filepath = Config.homePath? Config.homePath + '/' + filename : filename;
  const stream =  ytdl(id).pipe(fs.createWriteStream(filepath));
      stream.on('finish', (data) => {
        console.log(stream);
        this.mediaService.getAudioVolumes(stream).subscribe((d) => {console.log('done', d);});
      });
}

The service

import ffmpeg from 'fluent-ffmpeg-corrected';
import * as ffmpegBin from 'ffmpeg-static-electron';
import FS from 'fs';
import {Readable} from 'stream';
import {Config} from "../shared/config";

export interface IVolumes {
meanVolume: string;
maxVolume: string;
}

@Injectable()
export class MediaService {
  ffmpegPath = ffmpegBin.path
  .replace('app.asar/bin', 'app.asar.unpacked/' + this.binPath)
  .replace('node_modules/electron/dist/Electron.app/Contents/Resources/electron.asar/renderer/bin', this.binPath)
  .replace('browser/javascript', 'mac/x64') // TODO: platform hardcoded!
  ;

getAudioVolumes(stream: Readable | FS.WriteStream): Observable<IVolumes> {
  if (!Config.isElectron){
  this.ffmpegPath= 'node_modules/ffmpeg-static-electron/bin/mac/x64/ffmpeg';
  }
  ffmpeg.setFfmpegPath(this.ffmpegPath);
  
      return new Observable((observer: NextObserver<IVolumes>) => {
        const that = this;
        ffmpeg(stream)
          .withAudioFilter('volumedetect')
          .addOption('-f', 'null')
          .audioBitrate(128)
  
          .on('progress', function(progress) {
            console.log('Normalising Processing: ' + progress.percent + '% done');
          })
  
          .on('error', function(err) {
            console.log('An error occurred while analysing: ' + err.message);
            observer.error('DBs are not accessible');
          })
  
          .on('end', (stdout: any, stderr: string) => {
            const max = that.parseVolume(stderr, 'max_volume:');
            const mean = that.parseVolume(stderr, 'mean_volume:');
            console.log('volume analysis done, MeanDB is ', mean);
            observer.next({meanVolume: mean, maxVolume: max});
            observer.complete();
          })
          .save('/dev/null');
      });
}

TRY IT:

  1. Fork https://github.com/arcovoltaico/angular-electron
  2. Check out on the branch yt-dl
  3. run npm install on the root and also inside app/
  4. We need to hack the following node modules package.json by adding :
  1. Build the app by npm run electron:build
  2. Execute the app (releases/xxx) and click the Download Kraftwerk Button, you will see the error An error occurred while analysing: Output format null is not available

Upvotes: 1

Views: 936

Answers (1)

Alejandro Barone
Alejandro Barone

Reputation: 2151

After some debug I realize that the problem was in the utils.js file on the fluent-ffmpeg library, when it compares the instanceof Buffer it always says false because the Buffer created is a browserified Buffer instead of a strict node Buffer.

Why was this the error?, well, when you try to use the ffmpeg commands the library will check that the format passed (null in this case) is one of the available ones, it does this by running ffmpeg -formats wich returns, you guessed it, a Buffer (as any other ffmpeg command), so the validation was always saying that the format you passed was not "valid".

How you can fix this?, you can manually edit the node_modules by hand, changing the condition -maybe- to str.buffer instanceof ArrayBuffer. But a cleaner solution might be adding the Buffer as a pollyfil in the webpack config, like this:

  • Install buffer as a dev dependency npm install buffer -D
  • Add the following code on the angular.webpack.js in the plugins section
const webpack = require('webpack');
...
        config.plugins = [
        ...config.plugins,
        new webpack.ProvidePlugin({
          Buffer: ['buffer', 'Buffer'],
        }),
        new NodePolyfillPlugin({
              excludeAliases: ["console"]
        })
    ];

Not sure if it works on all cases but with that you can do the build command and check that the error is gone.

Another thing:

  • I realize that you are passing a WriteStream to ffmpeg which is odd as it should be a ReadStream, so maybe you will need to change that line to something like
  ffmpeg(FS.createReadStream((stream as any).path)

Hope it helps!

Upvotes: 1

Related Questions