Javaでビデオのトランスコード

  • 投稿日:
  • 更新日:2009/07/27
  • by
  • カテゴリ:

ちょいと画像やサウンドのトランスコードをやりたいと思いました。 ていうか、これまでも結構やってましたが、これまでこの手のものはCでバイト入出力で組んでいました。

CやC++で組むときも、Windowsなどのライブラリを使えば早いのでしょうが、UNIX文化というかJava文化に慣れきっているので、クロスプラットフォームにならない作り方はあまりしたくないのです。

で、クロスプラットフォームならと、ためしにJavaでやってみました。 Javaは仕事、というイメージがあるので、普段はあまり趣味で使いたいとは思わないのですが。

すると、既にAPIがそろいまくってるんですね。 ヘッダ解析からバイト単位で全部組んでいたのが嘘のようです。

サウンド関係はjavax.soundパッケージにそろっています。 標準パッケージのみだとmp3などのコーデックは入っていませんが、コーデックさえあれば同じAPIで使えるのが便利です。 たとえば、次のようなコードでアクセスできます。

AudioInputStream ais = AudioSystem.getAudioInputStream(new File("foo.wav"));
byte[] buf = new byte[ais.getFormat().getFrameSize()];

int bytes = ais.read(buf);

これで1フレームを取得できます。 フレームサイズとは、(1サンプルのバイト数) x (チャネル数)のことです。 たとえば、よく使う16ビットステレオであれば、2 x 2 = 4バイトということになります。 なお、フレームサイズ単位で取得する必要があります。

また、画像関係はjavax.imageioパッケージを使うと、やはりフォーマット非依存で似たような感じになります。 画像の各ピクセルに処理をしたいのであれば、たとえば以下のようにできます。

BufferedImage image = ImageIO.read(new File("foo.jpg"));
for (int y = 0; y < image.getHeight(); y++) {
  for (int x = 0; x < image.getWidth(); x++) {
    int rgb = image.getRGB(x, y);
    // ...
  }
}

もちろんこれは簡単な例で、さまざまな操作が可能です。


さて、問題は動画です。

調べてみましたが、Java Media Framework (JMF)というのがあります。 しかし、Java 2の標準APIには含まれていません。 また、最新のリリースが2003年ごろで止まっており、サポートしているフォーマットもあまりありません。 APIも貧弱です。

JMFのPerformance Pack (プラットフォーム固有のネィティブコードを使って高速に処理するライブラリ)をインストールしようとしたら、パソコンが固まってしまってにっちもさっちも行かなくなりました。 というわけで、ちょっと手を出しかねています。

ffmpegあたりと組み合わせて、(動画)->ffmpeg->(画像+サウンド)->ffmpeg->(動画)とすることも考えたのですが、いったん画像とサウンドを完全分離してしまうと、合わせるときにずれることがあるのであまり積極的にやりたい方法ではありません。

以前Cで組んでいたときは、このずれを心配したので、ffmpegで動画を変換し、フレーム単位で処理していました。 しかし、これをやりたい場合はjavax.imageioや、特にjavax.soundの恩恵をあまり受けられません。

う~ん、なかなかうまくいかないもんですね。 今のところは、ffmpegのフロントエンドのJffmpegあたりを使うしかないのですかねぇ。


こちらもよく読まれています