node.jsのいろいろなモジュール4 – Node Basic FFmpeg

2011.08.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Node Basic FFmpegとは?

ffmpeg(エフエフエムペグ)※1というソフトウェアをご存知でしょうか?
このソフトウェアは動画と音声を変換することのできるソフトウェアです。
対応するコーデックが豊富でコマンドラインから簡単に使用できるため、よく使用されています。
このソフトウェアを使用すれば、mp3をaacへの変換やmp4からflvへの変換など、ファイル形式変換が楽にできます。
このffmpegをラップしてnode.jsから使えるようにしたのが、Node Basic FFmpegです。
Node Basic FFmpegのgithub ※2に書いてありますが、現在対応しているのはLinuxだけのようです。
(今回私はMacで動作確認を行いましたが、バージョンによっては動かない可能性もあります)

セットアップ

今回紹介するモジュールはffmpegが必要なので、まずはffmpegをセットアップしましょう。
このあたりを参照すればインストールできると思います。
私の場合はhomebrewを使用してインストールしました。

$ brew install ffmpeg

これでffmpegとコーデックがインストールできます。
インストールできたらコンソールから実行できるのを確認しましょう。

$ ffmpeg -version
ffmpeg version 0.8, Copyright (c) 2000-2011 the FFmpeg developers
  built on Jul 13 2011 10:05:27 with gcc 4.2.1 (Apple Inc. build 5666) (dot 3)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/0.8 --enable-gpl --enable-version3 
  ・・・・・・
libswscale    2.  0. 0 /  2.  0. 0
libpostproc  51.  2. 0 / 51.  2. 0

もしffmpegコマンドが認識されていないならパスを通しておいてください。
次にffmpegディレクトリを作成し、そこでNode Basic ffmpegをnpmでインストールします。

$ mkdir ffmpeg
$ cd ffmpeg
$ npm install basicFFmpeg

これで準備ができました。
サンプルプログラムをうごかしてみましょう。
なお、本記事での動作確認環境は下記の通りです。

  • OS : MacOS X 10.7.1
  • Node.js : v0.4.10
  • ffmpeg : 0.8
    • サンプルを動かしてみる

      まずはmp3をoggに変換してみましょう。
      適当なmp3ファイルを用意して、ffmpegディレクトリに置いてください。
      次にmp3を変換するためのffmpeg.jsファイルを作成します。

      var ffmpeg = require('basicFFmpeg'),
          util = require('util'),
          fs = require('fs');
      
      //create input stream
      var inputStream = 
          fs.createReadStream('./inputSong.mp3')
          .on('end', function () {
              util.debug('input stream end');
          })
          .on('error', function (exception) {
              util.debug('input stream exception: ' + exception);
          })
          .on('close', function () {
              util.debug('input stream close');
          });
      
      //create output stream
      var outputStream = 
          fs.createWriteStream('./outputSong.ogg')
          .on('error', function (exception) {
              util.debug('output stream error: ' + exception);
          })
          .on('close', function () {
              util.debug('output stream close');
          })
          .on('pipe', function() {
              util.debug('a readable stream is now piping to output stream');
          });
      
      //create a new processor with options, listen for events and execute
      var processor = 
          ffmpeg.createProcessor({
              inputStream: inputStream //read from readable stream
            , outputStream: outputStream //write to writable stream
            , emitInputAudioCodecEvent: true //inputAudioCodec event will not be fired if this is not set to true
            , emitInfoEvent: true //info events will not be fired if this is not set to true
            , emitProgressEvent: true //progress events will not be fired if this is not set to true
            , niceness: 10 //set child process niceness to 10
            , timeout: 10 * 60 * 1000 //fire timeout event after 10 minutes, does not actually stop process
            , arguments: { 
                  '-ab': '128k'
                , '-acodec': 'libvorbis'
                , '-f': 'ogg'
              }
          })
          .on('info', function (infoLine) {
              util.log(infoLine);
          })
          .on('inputAudioCodec', function (codec) {
              util.debug('input audio codec is: ' + codec);
          })
          .on('success', function (retcode, signal) {
              util.debug('process finished successfully with retcode: ' + retcode + ', signal: ' + signal);
          })
          .on('failure', function (retcode, signal) {
              util.debug('process failure, retcode: ' + retcode + ', signal: ' + signal);
          })
          .on('progress', function (bytes) {
              util.debug('process event, bytes: ' + bytes);
          })
          .on('timeout', function (processor) {
              util.debug('timeout event fired, stopping process.');
              processor.terminate();
          })
          .execute();

      最初に入力ストリーム(inputSong.mp3)と出力するストリーム(outputSong.ogg)を作成しています。
      作成したストリームをcreateProcessor関数に渡し、コーデックやフォーマットを指定してexecute関数で実行しています。
      指定するオプションはffmpegのドキュメントを参照して適切な値を設定してください。
      では実行してみます。

      $ node ffmpeg.js
      DEBUG: a readable stream is now piping to output stream
      19 Aug 11:05:56 - ffmpeg version 0.8, Copyright (c) 2000-2011 the FFmpeg developers
      ・・・・・・・・
      19 Aug 11:05:58 - 
      DEBUG: process finished successfully with retcode: 0, signal: null
      DEBUG: output stream close

      デバッグメッセージが出力され、outputSong.oggファイルが生成されます。
      プレイヤーで再生してみると、ちゃんと再生できると思います。

      では次にaviファイルをflvファイルに変換するサンプルを記述してみましょう。
      先ほどのjsファイルの入力ストリームに、適当に用意したaviファイルを指定し、出力ストリームにflvファイル名を指定します。
      createProcessor関数内容を下記のように修正します。

          ffmpeg.createProcessor({
              inputStream: inputStream //read from readable stream
            , outputStream: outputStream //write to writable stream
            , emitInputAudioCodecEvent: true //inputAudioCodec event will not be fired if this is not set to true
            , emitInfoEvent: true //info events will not be fired if this is not set to true
            , emitProgressEvent: true //progress events will not be fired if this is not set to true
            , niceness: 10 //set child process niceness to 10
            , timeout: 10 * 60 * 1000 //fire timeout event after 10 minutes, does not actually stop process
            , arguments: {
                 '-f': 'flv'
      	 , '-ar':'44100'
              }
          })

      このプログラムを実行すると、flvファイルが出力されます。

      まとめ

      今回はffmpegラッパーであるNode Basic ffmpegを紹介しました。
      これを利用してWebアプリケーションでフォーマット変換する機能も実装できそうですね。
      また、Node Basic ffmpeg以外にもffmpeg用モジュールはいくつかあります。こちらも確認してみてください。

      • node-fluent-ffmpeg (https://github.com/schaermu/node-fluent-ffmpeg, author: Schaermu)
      • ffmpeg-node (https://github.com/xonecas/ffmpeg-node, author: xonecas)
      • node-simple-ffmpeg (https://github.com/scopely/node-simple-ffmpeg, author: hyperlight)


      次回もおもしろそうなnode.js用モジュールを紹介していきます。

      参考サイトなど