たくさんの自由帳
Androidのお話
たくさんの自由帳
投稿日 : | 0 日前
文字数(だいたい) : 19437
目次
本題
実際に動画編集してみた感想
ダウンロード
アプリの特徴
アプリの概要
その前に動画周りの技術について
コンテナの話
MediaExtractor
MediaMuxer
コーデックの話
動画エンコーダーの話
音声エンコーダーの話
Android で動画編集
今回の戦略
自分で作らないと無い機能
音声のサンプリングレート変換
音声の合成も無い
Canvas から動画を作る
動画のフレーム取り出すのが遅い
media3 の transformer は使わないの
transformer
akari-core
そのほか
Jetpack Compose は本当に便利
コルーチンは本当に便利
エンコーダーの設定
外部連携機能
まだ無い機能
おわりに
おわりに2
おわりに3
どうもこんばんわ。
D.C.5 Future Link ~ダ・カーポ5~ フューチャーリンク 攻略しました。(ぜんねんれい)
ファンディスクです。前作D.C.5では良くも悪くも(?)あのイベントにシナリオが引っ張られてた感があったけど、
今回はそれがなくて(?)ヒロインに合ったシナリオでかわいいな~ってなれる神ゲー。
あたしちゃん様!!!さすがファンディスクです
↑妹と話してるシーンよすぎ
!!!ヒロイン昇格!!
バカやってるのおもろい。無印では見れないのでファンディスクやろう!!!
↑ここすき
ファンディスクの割にフルプライスでお高いけどこのシナリオで元取った感ある!!
いい!
むんむん
かわい~、イベントCGよすぎ
でもみじか!!い!!もっと見たかった
体操服!
!!!本編では語られなかった部分の話、、だ!
あまあま
本編で書かれなかった部分、なかなか内容あるので見よう
うどんの話ししてる時に時そばだ
語られなかった部分の続きまで書いてくれるので結構ボリュームがある。
めっちゃ魔法の話でした
ついぞこの子を攻略することは出来ませんでしたが・・・!!
まだ謎が明かされてない箇所がありますが、D.C.6とかで明かされるんでしょうか。
何年後になるんだろう、、R-18版を出してからなのかな、どっちになるか分かんないけど楽しみ~
動画編集アプリを作ってみた。
かねてよりAviUtilとかの動画編集アプリってどうなってるんだろうって気になってたんですよね。大した機能はないですが、悲願であったアプリを作ることが出来ました。8888
(まあプラットフォーム違うからなんとも言えんけど)。
世の動画アプリの仕組みは知りませんが(バックエンドなのか端末内なのか)、このアプリは後者、端末内のMediaCodecでエンコードしています。
触ったことある動画編集アプリがAviUtilくらいしかないので、スマホの動画編集UIがどんな感じなのかは知らない。電気屋のAppleコーナーでiMovieちょっと触った程度ならあるよ。
MediaCodecシリーズの記事を書いてきた知見を合わせて作ってみた。
今回の記事はこれの中身の話です。
MediaCodec(とその周辺)を触るうえでの前提の話です。Androidで動画編集の話
MavenCentralにある)AkariDroid - Video editing app - Apps on Google Play
You can overlay text, images, and videos. Processing is done on the device.
https://play.google.com/store/apps/details?id=io.github.takusan23.akaridroid&hl=en_US
Android Studioでビルドできるんじゃないかな。GitHub - takusan23/AkariDroid: お正月なので動画の上にCanvasで落書きしてエンコードする
お正月なので動画の上にCanvasで落書きしてエンコードする. Contribute to takusan23/AkariDroid development by creating an account on GitHub.
https://github.com/takusan23/AkariDroid
フォアグラウンドサービスの審査用の動画、実際にこのアプリで作りました。
画面録画して編集して書き出してアップロードまでスマホで完結して結構感動。
(補足)
最近のPlay ストア、フォアグラウンドサービスを使う場合は起動方法を説明した動画を渡す必要がある。(どこかインターネットから見れる場所に上げてURLを記入する)
そのための動画をこれで作った。。。スマホで完結。
大した機能はない。
MediaCodecを叩いている
AndroidのAPIを叩いてるだけなので、インターネット接続も不要です。すてきIntentの仕組みを使って他のアプリで素材を作ってタイムラインに追加できますPixel 8ならAV1エンコードも夢じゃないかもあかりどろいどは、あかりこあとか言うcoreと、アプリのコードのふたつになっています。
なんで分かれてるかというと、coreの方はライブラリとしてMavenCentralにあるからなんですね。
あかりこあ:akari-coreは代わりにMediaCodecを叩いてくれるやつです。
叩いてくれるっても、このブログで扱ったことを集結させたくらいなので、地道にこれらを組み合わせていくしか無い。使用例はいつか書きます。
AkariDroid/akari-core/src/main/java/io/github/takusan23/akaricore/video/README.md at master · takusan23/AkariDroid
お正月なので動画の上にCanvasで落書きしてエンコードする. Contribute to takusan23/AkariDroid development by creating an account on GitHub.
https://github.com/takusan23/AkariDroid/blob/master/akari-core/src/main/java/io/github/takusan23/akaricore/video/README.md
AkariDroid/akari-core/src/main/java/io/github/takusan23/akaricore/audio/README.md at master · takusan23/AkariDroid
お正月なので動画の上にCanvasで落書きしてエンコードする. Contribute to takusan23/AkariDroid development by creating an account on GitHub.
https://github.com/takusan23/AkariDroid/blob/master/akari-core/src/main/java/io/github/takusan23/akaricore/audio/README.md
例えば動画をつなげる機能はない。
無いので、繋げたい動画のフレームを取り出しCanvasにかく。それを繋げたい動画が終わるまで続ける。みたいな。
この程度ならmedia3 transformerでいい気がするけど、今回のそれはそもそも考え方が違うのでそれは後半。
というかそもそもalpha01のままだわ。
implementation("io.github.takusan23:akaricore:2.0.0-alpha01")appモジュールのほうがアプリのコードになってて、タイムラインのUIとか、プレビュー用のUIをこっちで書いています。
2つもモジュールがあるのでGradle Version Catalog使ってみた。いつの間にかIDEのサポートが入ったのね。
で、この辺詳しく書こうと思ったんだけど、その前に動画周りの技術の話をしないとって思った。知ってる限りお話します。
この話は、AndroidのMediaCodecの話ではなく、動画全般の話になります。
が、MediaCodec/MediaExtractor/MediaMuxerが何をやるのかを理解するのには以下のキーワードが分からないと多分厳しいと思うので先に話します。
今日のテレビ会議から今晩のおかずまでを支える、動画の技術についてちょっとだけ触れます。
コンテナというのは、音声と映像を一つのファイルに格納するためのもので、mp4とかwebmとか言うあれです。
一緒にいれる箱でしか無いので、再生できるかどうかは中身次第になります。
一緒に格納したらどれがどれだか分からなくなりそうですが、トラックという概念があり、このデータは音声トラック、このデータは映像トラックと分かるようになっています。
ごくまれに、動画は流れるけど音量調整が出来ない動画がありますが、あれは映像トラックだけ再生できたパターンですね。音声トラックが無いのかエラーになったか。その逆もあると思う。
mp4は知りませんが、webmならこんな感じの構造だと思います。Clusterに音声と映像がそれぞれ書き込まれていくわけですね。多分映像データのが大きくなるのでこんな感じじゃないかな...
- demo.webm
- Header
- Segment
- Info
- Duration
- Tracks
- Track #映像
- Track #音声
- Cluster
- SimpleBlock #映像データ
- SimpleBlock #音声データ
- SimpleBlock #映像データ
- SimpleBlock #映像データ
- SimpleBlock #映像データこう考えてみると、なんか意地悪したくなりますね。mp4にAVCじゃなくてH.265(HEVC)入れたいよね。拡張子さえ見ればいいと思っている人を騙せそう(性格悪すぎ)
そういえば、Windows 11にするとH.265(HEVC)が無料で使えるらしい。
これでストアで数百円払わなくても再生できるぽい。
これは、.mp4 / .webmからそれぞれ音声と映像のデータを取り出すやつです。
そのほか、メタデータを取り出したりもできます(動画の縦横サイズ、動画の長さなど)
以下は擬似コードなのでそれっぽいですが多分動きません。
// MediaExtractor を作る
val mediaExtractor = MediaExtractor()
// ファイルを読み込む
mediaExtractor.setDataSource(context, uri)
// 映像トラックとインデックス番号のPairを作って返す
// 音声の場合は audio/ を探す
val (trackIndex, mediaFormat) = (0 until mediaExtractor.trackCount)
.map { index -> index to mediaExtractor.getTrackFormat(index) }
.firstOrNull { (_, track) -> track.getString(MediaFormat.KEY_MIME)?.startsWith("video/") == true } ?: return@withContext null
// トラック番号を指定する
// 映像トラックの番号
mediaExtractor.selectTrack(trackIndex)
// 映像データを取り出す
// エンコードされている(圧縮されている)ので、MediaCodec に渡します
val byteBuffer = ByteBuffer.allocate(1024 * 4096)
val readSize = mediaExtractor.readSampleData(byteBuffer, offset)
// MediaCodec なり...MediaExtractorの逆です。データを書き込みます。
これも以下は擬似コードなので動きません。
// MediaMuxer を作成
// 指定した Uri へ書き込む
val fileDescriptor = context.contentResolver.openFileDescriptor(uri, "r")
val mediaMuxer = MediaMuxer(fileDescriptor, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
// 映像トラックを追加
val videoTrackIndex = mediaMuxer.addTrack(videoMediaFormat)
// 開始
mediaMuxer.start()
// データがでてきたら書き込む
val byteBuffer = // 出てきたデータ
val bufferInfo = // 今の動画の時間とか
mediaMuxer.writeSampleData(videoTrackIndex, byteBuffer, bufferInfo)コーデックというのが、動画を圧縮するアルゴリズムのことですね。
そのアルゴリズムを動かすのがエンコーダーとデコーダーで、圧縮するのをエンコード、圧縮を戻すのがデコードです。
パラパラ漫画の一枚一枚のことを動画ではフレームとか呼んだり。そのフレームが一秒間に何回あるかがフレームレートですね。
30fps なら 30 回フレームが切り替わりますし、120fps なら 120 回フレームが切り替わるわけですね。
ちなみに、ミリ秒で表すと30fpsは33ミリ秒毎に、60fpsなら16ミリ秒毎に切り替わるわけです。すごいね。
で、で、で、動画はパラパラ漫画みたいになっていますが、パラパラ漫画のようにすべての画像を持っているといくら容量があっても足りません。
てか容量だけじゃなくて通信量が先に終わってしまいます。

↑ 手元で見たら 1920x1080 の1フレームが 1MB だった。30fps なら1秒で 30MB になりますね。1分で・・・うっ
そこで、コーデックが圧縮をするわけですね。例えば、前のフレームと比較して、変化している箇所のみをファイルに保存する。とか。
ただ、一生前のフレームとの差分を持っていると、今度はシークができなくなってしまう(このままだと、ちょっと後ろに戻したいだけなのに、最初から差分を見ていく必要がある。)
なので、前のフレームに依存しない、完全なフレームを定期的に入れるわけですね。1秒毎とか。これをキーフレームといい、間隔のことをキーフレーム間隔とかなんとか。
(キーフレーム。別名同期フレーム、Iフレーム)
Firefoxの自動再生がデフォルトONになる話で、仮にデフォルトOFFにしちゃうとパラパラ漫画を実装されて、かえって通信量が増えるからONにしてるって見た気がする。
Firefox 66 to block automatically playing audible video and audio – Mozilla Hacks - the Web developer blog
Unsolicited volume can be a great source of distraction and frustration for users of the web. So we are making changes to how Firefox handles playing media with sound and ...
https://hacks.mozilla.org/2019/02/firefox-66-to-block-automatically-playing-audible-video-and-audio
前のフレームとの差分しか持ってないから小さく出来てる。一方動画の逆再生がかなり難しいという話は前した気がする。
コーデックにもいくつか種類があり、まず映像から。音声は後述。
AVC(H.264)HEVC(H.265)AVCの半分のビットレート(半分の容量・通信量)で同じ画質になるらしいVP9AV1
-ロイヤリティティーフリーかつHEVCと同等の効率らしい
Pixel 8にはAV1 ハードウェアエンコーダーあるけどそれ以外はまだなさそう。先取りだね)あ、あとビットレートってのが1秒間にどれだけデータを使うかで、多ければ画質が上がります。
音声なら 192kbps ? か 128kbps。動画ならコーデックにもよるけど 10Mbps あれば高画質?
次は音声エンコーダー周りの話。
ビットレートは音声エンコーダーにもあるんですが、動画のそれと同じなので割愛。
チャンネル数はモノラルなら1、ステレオなら2です。
モノラルの場合は左右から同じ音が、ステレオなら左右から違う音が出ます。まあほとんどステレオだと思います。
サンプリングレートは、一秒間に何回音声を記録するか。で、
44100 か 48000 の2つが多分主流です。ニコニ・コモンズとかにある音声素材は変なサンプリングレートのがあるけど。
で、で、で、Opusとかいうコーデックが44100対応していないので、48000にしておくといいかも。
(今回の動画編集アプリでは48000に統一した)
あと、量子化ビット数が音声データの記録に何バイト分使うかですね。まあ16bit(2バイト分)じゃないですかね。ほとんど。
最後はPCMの話。これは音声データの生データのことを指します。aacやopusとかのファイルはエンコードされているので、デコードする(圧縮を戻す)ことでPCMを得ることが出来ます。
0x00で無音のデータを作ってみました。(2チャンネル、16bit (2バイト))
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00↑実際のデータはこんな感じになってて、(0x00なので無音ですが)
2バイトずつで見ていきます。最初の2バイトが左、次の2バイトが右の音声です(ごめん左右逆かも。)。2チャンネルあって、16bitなので、一回のサンプリングに4バイト(2*2)使うわけですね。
この例だと2つのサンプルしか無いですが、一秒間にサンプリングレートの回数分繰り返されるはずです。
繰り返されるだけなので、これは計算でPCMを作るのにどれだけの容量が必要か出すことが出来ます。
例えばチャンネル数 = 2 / サンプリングレート = 48000 / 量子化ビット数 = 16bit (2バイト)なら、1秒間に 2 * 48000 * 2 = 192000 byteですね。
音声コーデックはこんな感じ
AACmp4の中に入ってる音声多分このコーデックがほとんどじゃない?OpusWebMに入る音声コーデックはAndroidで使えるやつだとこれだけ?44100が使えないらしい(ので、48000になるようにサンプリングレートの変換が必要)以上!今日の動画と音声の話!
は厳しい。なぜならろくなAPIが存在しない。
(最近media3 transformerが出たそうです。が、要件満たせなそうでMediaCodec叩いてる。バンバン)
本題です。iOSはiPhone普及期(まだiPhoneに機種変するなら、iTunesを動かすためのパソコンがないとダメって言われたた頃!)からiMovieとかいうアプリがあったので、動画編集周りは割とマシなAPIがあるらしい?(iPhoneには明るくないのでネット情報でしか無い)
一方Android・・・?エンコードとデコードが出来るMediaCodecとかいうやつがAndroid 5くらいからあるけど、、、
入力として音声ならバイト配列、映像ならSurfaceを受け付けて、エンコードしたデータを吐き出す。エンコードとデコードという最低限の機能しかない。
(Surfaceってのは、なんか映像を運ぶパイプみたいなやつ。カメラ映像とか再生中の動画フレームとか。これのおかげでバイト配列でやり取りしなくてすむ。)
(ブラウザのgetUserMedia()がStreamを返すじゃん、あれに近い。)
お友達にMediaExtractor (コンテナフォーマットから取り出す)とMediaMuxer (コンテナフォーマットに書き込む)がいるけど。。。
動画を司る最低限のAPIならあるけど、動画編集で使えるAPIは無いので、全部自前で書かないといけない。
ちなみに、MediaCodecのAPI、すごいドキュメントが長いけど何も分からないが得られます。
どうやって動画を作るか。編集するか。
というわけで今回の戦略。Canvasで動画のフレームを作って渡す。音声はデコードして合成する。
SurfaceTextureを使って映像を渡しつつ、Canvasで落書きをするというのがあり、初期段階ではこれを使おうと思ってました。
AndroidでMediaCodecを利用して動画の上に文字をかさねる - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_add_canvas_text_to_video/
(SurfaceTextureはカメラ映像とか動画のフレームをOpenGLのテクスチャとして使えるやつ。)
ただ、前書いた記事の方法では満たせない要件があったため、、、この方法は却下になり、作り直しになりました。
AviUtilとかはこの動画に動画を重ねたり、動画を2つ並べて再生が出来るので、この機能も実装したい。SurfaceTextureが一つしか無いので。MediaCodec - Surface - OpenGL ESみたいな感じで、エンコーダーと描画のOpenGL ESが強く紐付いちゃってますOpenGLをセットアップするのはやりたくない。。。
OpenGL ES詳しくないしCanvasも更新していくCanvasを重ねてエンコードした時のフレームに限りなく近いものが表示されることになります。
MediaCodec - OpenGL ES、プレビューの方はただ動画を流して上にCanvasを表示させているだけになってしまう
Canvasで作る方法が結構いいという確信がある
Canvasから動画を作る
MediaCodecで逆再生の動画を作る

AndroidのMediaCodecで逆再生の動画を作る - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_mediacodec_reverse_video/
Canvasに書き込んでエンコードするというもの
Canvasに書けば、難しいSurfaceTexture周りを触らずに完結するという知見が得れたAndroidの動画からフレームを取り出すMediaMetadataRetrieverがとても遅いことも同時に判明MediaMetadataRetrieverが遅いので、MediaCodecを叩いて高速にフレームを取り出す処理を作る

Android で動画からフレーム(画像)を高速で取り出す処理を自作する - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_get_video_frame_mediacodec/
MediaMetadataRetrieverよりはずっと速いですが、それでもプレビューに数秒かかります。どうしよう。Canvasで書けるなら動画編集アプリ行けるんじゃね?←これ作戦変更後は、Canvasに動画のフレームを書き込む方法になります。Canvasは高レベルなのでメンテしやすそうなのと、上記の問題もほぼクリアできます。
Canvasに文字と画像を書いてエンコーダーに渡せばいい。Canvasで書けばいいので。Canvasに書ければいいのでCanvasで描く処理を作るだけ!
Canvasで書いたのをBitmapでもらってJetpack Composeで書けばいい。Canvasで書いたのをBitmapにしてOpenGL ESで描画した後エンコーダーに流せばいい。Canvasで書く部分が、プレビューとエンコードで共通化出来たことにより、プレビューで使われるフレームは実際にエンコーダーにも送られるフレームになります。
media3を消せました。ExoPlayer つかってない · takusan23/AkariDroid@8099545
https://github.com/takusan23/AkariDroid/commit/8099545b2f3e11e2421bed3c5084a4cf076e58bb
具体的なコードはこの辺です。
ちなみに、OpenGL ESはハードウェアアクセラレーションされた描画システム?がAndroidのMediaCodecでは必要なので、OpenGL ESから逃げることは出来ないぽい。
動画編集APIなんて無いので、自分で作る必要があるのですが、その中でも大変だったのを
音声のサンプリングレート変換はありません。どこでサンプリングレート変換が必要かと言うと、無いとこの次の合成ができないんですよね。
音は波(らしい)ので、同じ位置のデータをそのまま足し算すれば音を合成できるのですが、(PCM 音声 合成とかで調べてみて)
// 16 bit と仮定
pcm1: 0x0001 0x0001 ...
pcm2: 0x0002 0x0002 ...
-------------------------
sum0: 0x0003 0x0003この、足し算の際に合成したい音声のサンプリングレートをあわせておく必要があります。
しないと音声が早くなったり遅くなったりして期待通りになりません。
というわけで、割と使いそうな気がするこのサンプリングレート変換する方法、Androidにはありません!!!
内部的にはあるんだろうけど、、、サードパーティ開発者が使えそうなのはなくて困った。
というわけで調べた。
ちょうどその頃、media3もなんか動画変換処理を作ったとか言ってて(media3 transformer)、作ったってことはおそらくサンプリングレート変換がない問題を知ってるはずでしかも解決してそう!
どうやってるんだろって見に行ったらsonicというのを使っていました。純粋なJava実装らしく、Androidでも動いちゃいます。
OSSに頼りました。File not found · takusan23/AkariDroid
お正月なので動画の上にCanvasで落書きしてエンコードする. Contribute to takusan23/AkariDroid development by creating an account on GitHub.
https://github.com/takusan23/AkariDroid
ちなみに、元のサンプリングレートの取得でAndroidのMediaExtractorを使うと罠があります。前話した通りですが、HE-AACを入れるとサンプリングレートが何故か半分になる。MediaExtractorのMediaFormatではなく、MediaCodec#getOutputFormatの方のサンプリングレートは正解なので、そちらを信用する必要があります。(まじで謎)
音声の合成もない。
本当に何も無い。
ただ、先述の通り、音声の合成は同じ位置のデータを足し算すればいい(単純なやつなら)ので、サンプリングレート変換よりもずっとマシなはず。
一点!足し算の際に、量子化ビット数が16bit の場合 0xFFFF を超えないようにする必要があります。超えたら音割れポッターなります。
なので、元の音声素材の音量を小さくするとかの対策が必要です。PCMなので、小さくするのも 2 バイトを Int にして、0.5とか掛け算して小さくした後、2バイトに戻せばいいと思う。
そういえばOutputStreamってBufferの方を使うか、バイト配列にいくらか溜め込んでから書き込むかしないと遅いんですね。write()でファイルを開けるのが重たいんでしょうか。ちなみにbufferd()する方にしました。
ちなみに今回は単純に足したのであれですが、pcm audio mixingとかで調べると色々な案が出てくるので、おそらくちゃんと調べるべきです。
単純に足せばいいというわけではないらしい。まあ元の音量をいじって合計が0xFFFFを超えないようにするって作業、現実だとそんな事しないよな。それはそう。
これは前書いた記事の通りです、これは自分で作らないと流石に無いですね。
逆再生のほうがちょっとだけきれいなコードかも(単純に後に書かれたってことで)。

AndroidでCanvasから動画を作る - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_canvas_to_video/

AndroidのMediaCodecで逆再生の動画を作る - たくさんの自由帳
https://takusan.negitoro.dev/posts/android_mediacodec_reverse_video/
これも前書いた記事の通り。
実は伏線だったんですね。あの記事。
そういえば、Androidに動画編集APIがないみたいな話をしましたが、最近media3 transformerが出たようです。
ただ、私のそれとは思想が違いそう。
transformerって名前なので、動画編集よりも、動画をリサイズするとか、音声トラックを消すとか、いらない部分をカットするとか、画像を重ねたいとか、元ある動画を変換するのに使う?。
プレビュー機能は無いらしい(今後できるらしい)、あとは動画無しでは使えない?みたい。動画の上に動画を重ねる機能は将来出来るらしい。
うーん。思想的には動画編集!って感じのAPIではなく、
メッセージアプリで、動画を小さくしてかつカットしたいけど動画周りは自前で作りたくないよ~><。みたいな時に使えばいい雰囲気がある。
画像と文字だけで動画を作りたいみたいなユースケースは対応してなさそう感じがする。(transformerって名前だしそりゃそうか)
でもでもでもOpenGL ES / MediaCodec周りを触らずに、動画の上に文字を重ねることが出来るとか素晴らしすぎる。
この↓の記事書いてたときはそんなの無かったよ?(たしか)
一方私のはCanvasに書ければ何でも出来るみたいな感じで作ったので、フレームが取れるなら何個でも動画を並べられる。Canvasに描きたいものがある限りエンコーダーにフレームを流せる。Canvasから作るので動画がなくても作れます。
でも動画のカットとかはパットは実装できず、指定時間だけフレームを取り出して、Canvasに書き込むような使い方をしないといけない。
複数の動画をつなげるのも、動画からフレームを取り出してCanvasに書いて、フレームがなくなるまで続けて、無くなったら次の動画ファイル・・・って感じでやる必要があり、これもやっぱりすぐには作れない。
その上、音声トラックのことは別に考慮する必要があり、これもカットや結合も自分で書かないといけないので、やっぱりすぐには作れない。
(デコードしてPCMにしたあと、指定時間だけ取り出す、PCMを連結させる等してPCMを加工したあとエンコーダーに入れる)
うーん。こうしてみると、"動画編集ライブラリ"よりも"MediaCodecを代わりに叩くライブラリ"のほうが自己紹介としては正解かもしれない。
あんまり動画の話はなくなってきます

Drag, swipe, and fling | Jetpack Compose | Android Developers
https://developer.android.com/develop/ui/compose/touch-input/pointer-input/drag-swipe-fling
Modifier.pointerInputとdetectDragGesturesありがとう。今ならリストの並び替えも作れそう。(それはどうだろう、それはそうとMotionEvent辛かったよな・・・)
あと地味にIntRectに使いたい関数生えてていい!
どっちかと言うとFlowをいっぱい使いました。
タイムラインに素材を追加したら、プレビューも更新しないといけないんですが、もうFlowを購読して勝手に反映されるようにしました。
collectLatest { }、すでに処理中だったらキャンセル投げてやり直してくれるので、重たい処理がある場合は地味に便利。
// 素材が更新されたらプレビューにも反映
viewModelScope.launch {
_renderData
.map { it.audioRenderItem }
.distinctUntilChanged()
.collectLatest { renderItem ->
videoEditorPreviewPlayer.setAudioRenderItem(renderItem)
}
}
viewModelScope.launch {
_renderData
.map { it.canvasRenderItem }
.distinctUntilChanged()
.collect { renderItem ->
videoEditorPreviewPlayer.setCanvasRenderItem(renderItem)
// プレビューを更新
videoEditorPreviewPlayer.playInSingle()
}
}オペレーターが便利すぎる。map { }で加工していく感じ、書いてて楽しい。
// 動画の情報が更新されたら
viewModelScope.launch {
// Pair に詰めて distinct で変わったときだけ
_renderData
.map { Pair(it.videoSize, it.durationMs) }
.distinctUntilChanged()
.collect { (videoSize, durationMs) ->
videoEditorPreviewPlayer.setVideoInfo(videoSize.width, videoSize.height, durationMs)
_timeLineData.update { it.copy(durationMs = durationMs) }
_touchEditorData.update { it.copy(videoSize = videoSize) }
}
}コーデック、いくつか選べるようにしました。せっかくハードウェアエンコーダーが乗ってるなら選べるようにしたら面白いかなって思った。Pixel 8からAV1 ハードウェアエンコーダーが乗ってるので、AV1 コーデックも選べるようにしました。Android 14 からはAV1 ソフトウェアエンコードもできます。
外部連携機能があります。あかりんく。
これは外部アプリで素材を作成(写真とか)して、その素材をタイムラインに追加できる機能で、
標準では作れない、なんか特殊な素材(例えばQRコード画像生成機能とか)を外部アプリで作成して、あかりどろいど側で受け取る事ができます。
技術的には、AndroidにはIntentで他のアプリと連携できる仕組みがあります。それこそ大昔(?)のキーボードアプリのマッシュルーム機能とかはこのIntentで出来ていたはず。
これを使ってます。
写真をメッセージで送る時に標準のカメラアプリが起動するやつ。あれ。
流れとしては、
Intentを投げる(startActivity)
Intentを受け取れるように、AndroidManifest.xmlで定義するIntentからUriを取り出す
Uriに、音声、画像、動画を書き込みますsetResultを呼び出し、以下の情報を詰めてください
Intent#setTypeにMIME-TypeUriに何のデータを書き込んだか分からないためEXTRA_TITLEで素材の名前を変更できます。finish()を呼ぶことで、元いたあかりどろいどに戻ってこられるはずActivity Result APIのコールバックが呼ばれて、タイムラインに追加されますAkariDroid/AKALINK_README.md at master · takusan23/AkariDroid
お正月なので動画の上にCanvasで落書きしてエンコードする. Contribute to takusan23/AkariDroid development by creating an account on GitHub.
https://github.com/takusan23/AkariDroid/blob/master/AKALINK_README.md
ちなみに、似たような機能を作りたい場合ですが、FileProviderクラスを見てみてください。外部アプリとIntentに入り切らないバイナリデータをやり取りするやつです。Uriを経由しないと多分怒られる(画像をIntentに入れると多分サイズデカすぎで落ちる)
まさかのローカライズすらしていない。Text(text = "ハードコーディング!")
つかれた。Playストアで動画編集アプリ探すと結構でてくるけど、動画編集アプリ作ってわかった。(大した機能はないけど)
世のAndroidで動く動画編集アプリはよくやっていると思います。Androidろくな動画編集API無いんだよ?
画面小さすぎて操作しにくい。
そういえば、あかりこあ(akari-core)、これAndroid 5以降で動くはずなのですが試してなかったので試しました。結果Xperia Z3 Compact (Android 5)っていう名機でも動きました。
わんちゃんAndroid 5以降が動いてる端末なら何でも動く説がある。Androidのらくらくホンとか。Androidで動いてるなんか変なやつ(例えが出ないけど)
見た感じmedia3 transformerも同じくAndroid 5以降で動きそう。試せてはない
ちなみにあかりどろいど自体はちょっと直さないと動かなそう。(超小声)
エンコード部分はちゃんと動きました。それ以外の部分がちょっと壊れてた。。
MediaMetadataRetriever、AutoCloseableを実装してるの新しいAndroidだけなのか、、罠すぎる