LoginSignup
15
14

More than 5 years have passed since last update.

Androidで動画編集アプリを作るならmedia-for-mobile

Posted at

media-for-mobile

INDExOSがOSSとして公開している動画編集系のフレームワーク
Apache License 2.0で利用できる
例えばOpenGLESのprogramをProgramクラスが担っていたり基本的に生のOpenGLESを利用せずにラップしているクラスを介して処理している。
まだ6コミットで今年の頭に登場した。
java製


プラットフォーム

Supported Android versions: Jelly Bean 4.3 or higher


導入

Gradleで入れる事は出来ないのでモジュールとして入れる。
機種依存系の修正は絶対何処かでする事になるのでコンパイルせずに入れるのが良かった。


サンプル

/samples以下がそれにあたる


出来る事

動画の連結
動画エフェクト追加
音声エフェクトの追加


基本

mediaComposer = MediaComposer(factory, progressListener)
mediaComposer?.start()

MediaComposerを生成し、そこにメディアを追加して処理する。

引数のprogressListenerには

public void onMediaStart();
public void onMediaProgress(float progress);
public void onMediaDone();
public void onMediaPause();
public void onMediaStop();
public void onError(Exception exception);

が生えている。内部ではわりと浅い位置にtry/catchのブロックでエラーハンドリングが行われているので機種依存などで処理が終わらない時等はさっさとカスタムExceptionを返してonErrorで処理を分けると良い。


機能


ビデオフォーマット指定

mediaComposer.targetVideoFormat = videoFormat

で指定する。

val videoFormat = VideoFormatAndroid(transcodeConfig.videoMimeType, width, height)
videoFormat.videoBitRateInKBytes = transcodeConfig.videoBitRateInKBytes
videoFormat.videoFrameRate = transcodeConfig.videoFrameRate
videoFormat.videoIFrameInterval = transcodeConfig.videoIFrameInterval

フレームレートは指定しても特に変化はなかった、内部的にはこのパラメータをMediaCodecのsetIntegerしているだけなのでMediaCodecのフレームレート指定と同じ挙動をしているということだと思う。


オーディオフォーマット指定

val aFormat = AudioFormatAndroid(transcodeConfig.audioMimeType, audioFormat?.audioSampleRateInHz ?: 44100, audioFormat?.audioChannelCount ?: 1)
aFormat.audioBitrateInBytes = transcodeConfig.audioBitRate
aFormat.audioProfile = MediaCodecInfo.CodecProfileLevel.AACObjectLC
mediaComposer.targetAudioFormat = aFormat

こちらもMediaCodecへの設定渡しをラップしてくれているクラスを利用する。


連結

mediaComposer = MediaComposer(factory, progressListener)
mediaComposer?.addSourceFile(video1)
mediaComposer?.addSourceFile(video2)
mediaComposer?.start()

addSourceFileした順に動画が連結される。
指定位置に差し込むinsertSourceFileもある


トリミング

val trimRange = Pair(10000,200000)
val mediaFile = mediaComposer.sourceFiles[0]
mediaFile.addSegment(trimRange)

メディアは一度addSourceFileしたあと、sourceFilesからMediaFileクラスとして取り出せる。
そこに対してaddSegmentと、範囲情報を与えるとトリミング範囲を指定出来る。


エフェクト

VideoEffectクラスを継承して実装する。
setFragmentShaderが生えているので、そこに自分で書いたフラグメントシェーダを指定するとOpenGLES2のエフェクトがかけられる。
いちいちビルドするのは現実的じゃないので
http://www.kickjs.org/example/shader_editor/shader_editor.html#
等でシェーダを作ってからコピペするのが良い。
フラグメントシェーダはKotlinで書くとヒアドキュメントが使えて良い。
またエフェクトを重ねがけする場合は一度エンコードしてから再エンコードする。同時刻に2種類以上のエフェクトが存在する場合は後からかけられたエフェクトが優先される。


プレビュー

プレビュー機能は提供されていない。
プレビューを使いたい場合はSurfaceTextureなどで自作するのが良い、エフェクトのプレビューはVideoEffectクラスから取れるシェーダーを適用させて毎フレームaddEffectSpecificを呼ぶとレンダリング結果と同じプレビューをレンダリング出来る。


キャプチャ

ゲームキャプチャとカメラキャプチャ機能もあるが、サンプル止まりなので自分で作ったほうが良さそうだった。


上手く動かなかったところ


SamsungGalaxyS6ではレンダリング後の動画がノイズだらけになることがある。

トリミングをした時のみ発生する問題で、トリミング範囲を100ms程度ずらしてノイズの乗らない位置を探すと良い。
この問題が発生する時はMuxRenderクラスのwriteSampleDataメソッドでのsampleTimeが大きくずれたり張り付いたりするのでそれを検知すると上手くいく。
音声エフェクトをかける際もこの問題がおきやすかった。


Xperiaの一部機種で処理が終わらない事がある

何らかが原因で処理が抜けてしまいパイプラインから迷子になるっぽい、タイムアウトを設けて過ぎてしまったら強制的に処理を終了させるなどの対策をすると良い。

15
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14