[Android Tips] mp4parser を使って動画ファイルを編集する

2014.05.16

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

Android で動画編集

Android の動画編集は Android 4.1 (APIレベル16) からできるようになりましたが、4.1 以下で対応するためには標準 API ではできません。そこで、Google が公開している mp4parser という mp4 形式の動画ファイルを編集するライブラリがあるので、ちょっと使ってみました。なお、サンプルコードは以下で公開していますので、お急ぎの場合はこちらを Clone して実行してみてください。

https://github.com/suwa-yuki/Mp4ParserSample

ちなみに assets ディレクトリに mp4 ファイルのサンプルを用意しました。こちらを端末の外部SDカードの直下に置くと読み込めるようになります。

ライブラリの導入

mp4parser ライブラリは Maven を使うか jar ファイルを取り込むかいずれかの方法で導入できます。今回は手軽に jar ファイルをダウンロードしてくることにしました。以下の URL からダウンロードできます(今回は 1.0.1 を使います)。

http://repo1.maven.org/maven2/com/googlecode/mp4parser/isoparser/

なお、aspectjrt に依存しているので、こちらも一緒に入れてください。

http://repo1.maven.org/maven2/org/aspectj/aspectjrt/1.7.3/

試してみる

オリジナル動画

以下の動画を編集します。動画は動画素材.comさんからお借りしました。美味しそう!

複数の動画ファイルを1つにする

それでは試してみます。以下は2つの mp4 ファイルを1つにまとめる処理です。

private boolean append() {
  try {
    // 複数の動画を読み込み
    String f1 = Environment.getExternalStorageDirectory() + "/sample1.mp4";
    String f2 = Environment.getExternalStorageDirectory() + "/sample2.mp4";
    Movie[] inMovies = new Movie[]{
            MovieCreator.build(f1),
            MovieCreator.build(f2)};

    // 1つのファイルに結合
    List<Track> videoTracks = new LinkedList<Track>();
    List<Track> audioTracks = new LinkedList<Track>();
    for (Movie m : inMovies) {
        for (Track t : m.getTracks()) {
            if (t.getHandler().equals("soun")) {
                audioTracks.add(t);
            }
            if (t.getHandler().equals("vide")) {
                videoTracks.add(t);
            }
        }
    }
    Movie result = new Movie();
    if (audioTracks.size() > 0) {
        result.addTrack(new AppendTrack(audioTracks.toArray(new Track[audioTracks.size()])));
    }
    if (videoTracks.size() > 0) {
        result.addTrack(new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()])));
    }

    // 出力
    Container out = new DefaultMp4Builder().build(result);
    String outputFilePath = Environment.getExternalStorageDirectory() + "/output_append.mp4";
    FileOutputStream fos = new FileOutputStream(new File(outputFilePath));
    out.writeContainer(fos.getChannel());
    fos.close();
  } catch (Exception e) {
    return false;
  }
  
  return true;
}

実行結果

処理には少し時間がかかるので、AsyncTaskLoader などを使って非同期で処理を行いましょう。ファイルサイズが大きくなる場合は Service を使ってしまったほうが良いかも知れません。

動画ファイルを分割する

次に1つの動画ファイルを分割する処理です。

private boolean crop() {
  try {
    // オリジナル動画を読み込み
    String filePath = Environment.getExternalStorageDirectory() + "/sample1.mp4";
    Movie originalMovie = MovieCreator.build(filePath);

    // 分割
    Track track = originalMovie.getTracks().get(0);
    Movie movie = new Movie();
    movie.addTrack(new AppendTrack(new CroppedTrack(track, 200, 400)));

    // 出力
    Container out = new DefaultMp4Builder().build(movie);
    String outputFilePath = Environment.getExternalStorageDirectory() + "/output_crop.mp4";
    FileOutputStream fos = new FileOutputStream(new File(outputFilePath));
    out.writeContainer(fos.getChannel());
    fos.close();
  } catch (Exception e) {
    e.printStackTrace();
    return false;
  }
  return true;
}

実行結果

ちょっとバグってますね・・・(´・ω・`)

動画ファイルに字幕を入れる

次に動画ファイルに字幕を入れる処理です。映画の字幕みたいな感じですね。

private boolean subTitle() {
  try {
    // オリジナル動画を読み込み
    String filePath = Environment.getExternalStorageDirectory() + "/sample1.mp4";
    Movie countVideo = MovieCreator.build(filePath);

    // SubTitleを追加
    TextTrackImpl subTitleEng = new TextTrackImpl();
    subTitleEng.getTrackMetaData().setLanguage("eng");

    subTitleEng.getSubs().add(new TextTrackImpl.Line(0, 1000, "Five"));
    subTitleEng.getSubs().add(new TextTrackImpl.Line(1000, 2000, "Four"));
    subTitleEng.getSubs().add(new TextTrackImpl.Line(2000, 3000, "Three"));
    subTitleEng.getSubs().add(new TextTrackImpl.Line(3000, 4000, "Two"));
    subTitleEng.getSubs().add(new TextTrackImpl.Line(4000, 5000, "one"));
    countVideo.addTrack(subTitleEng);

    // 出力
    Container container = new DefaultMp4Builder().build(countVideo);
    String outputFilePath = Environment.getExternalStorageDirectory() + "/output_subtitle.mp4";
    FileOutputStream fos = new FileOutputStream(outputFilePath);
    FileChannel channel = fos.getChannel();
    container.writeContainer(channel);
    fos.close();
  } catch (Exception e) {
    e.printStackTrace();
    return false;
  }
  return true;
}

実行結果

subtitle_sample

↑ Galaxy S3 で再生したときのキャプチャです。下のほうに字幕が表示されます。

まとめ

今回の例以外にも、いくつかできることはあるのでこちらのサンプルコードを参考に実装してください。

動画を用いたアプリはあまり多くないと思うので、このライブラリを使って面白い動画アプリを作りたいですね!ぜひ使ってみてください。