Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
「騒ゲーハイライト」について【MIXI TECH CONFERENCE 2023】
Search
YuukiARIA
March 02, 2023
Technology
1
1.1k
「騒ゲーハイライト」について【MIXI TECH CONFERENCE 2023】
MIXI TECH CONFERENCE 2023 Day 1 でお話したスライドです。
https://techcon.mixi.co.jp/d1-3
YuukiARIA
March 02, 2023
Tweet
Share
More Decks by YuukiARIA
See All by YuukiARIA
Game Development Tutorial 2021
yuukiaria
0
25k
リアルタイム通信をささえるブラナイのサーバー開発と運用(前編)
yuukiaria
1
970
Other Decks in Technology
See All in Technology
Evolutionary Architecture - Discovering Boundaries @DevTalks 24
victorrentea
1
270
240524「開発生産性を、もっと誇れる組織へ」という方針を 9ヶ月前に掲げたCTOの振り返り
msykd
PRO
0
440
Oracle Database 23ai Overview
oracle4engineer
PRO
0
320
HeadlessなUIライブラリを利用する価値
plaidtech
PRO
10
3k
AWS でのクラウド時代のログ活用
itotsum
1
140
プロダクトオーナー向け生成AI支援サービスの仮説検証事例
yosuke_matsuura
PRO
1
200
SREがいない”今いる場所”で 「SRE」について聞いて、考えてみた
maimyyym
1
220
機械学習モデルの運用と実用的なアプローチ
databricksjapan
0
260
Platform Engineering on Serverless
_kensh
3
440
React 19を概念から理解する
uhyo
19
6.3k
まずは開発組織を整えるところからはじめる
ichimichi
0
110
データベース06: SQL (3/3) 副問い合わせ
trycycle
0
120
Featured
See All Featured
The Invisible Side of Design
smashingmag
294
49k
A better future with KSS
kneath
231
17k
5 minutes of I Can Smell Your CMS
philhawksworth
199
19k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3.1k
Git: the NoSQL Database
bkeepers
PRO
423
63k
Designing with Data
zakiwarfel
96
4.9k
KATA
mclloyd
16
12k
The Mythical Team-Month
searls
217
42k
What's in a price? How to price your products and services
michaelherold
238
11k
Faster Mobile Websites
deanohume
300
30k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
4
200
How to train your dragon (web standard)
notwaldorf
76
5.3k
Transcript
©MIXI MIXI TECH CONFERENCE 2023 「騒ゲーハイライト」について 開発本部 CTO室 クライアントグループ Yuki
Shinobu
©MIXI Yuki Shinobu / YuukiARIA 株式会社MIXI 開発本部CTO室クライアントグループ 2014年新卒入社。 直近ではゴーストスクランブルのテクニカルリードとして 主にクライアントの技術課題に取り組む。
2 自己紹介
©MIXI 本日の内容 • ゴーストスクランブルと「騒ゲーハイライト」システム • Unityゲーム画面のキャプチャ • Androidでmp4動画を出力するまで • 様々な不具合対応
3
©MIXI ゴーストスクランブルについて
©MIXI ゴーストスクランブル モンストシリーズの協力アクションスマホゲーム ストブルと略します 5 ゲームエンジン グラフィック サウンド Unity 2020.3
Universal Render Pipeline (URP) CRI ADX
©MIXI 「騒ゲーハイライト」とは? ゲームプレイの特定の15秒を動画として保存できる機能 6
©MIXI 基本の設計コンセプト
©MIXI システムの要件 • キャプチャ実行時,直前の10秒程度を含む前後の動画を保存 • インゲームプレイ中,いつでもキャプチャ実行可能 • 保存した動画はSNS等へ投稿できる形式 ◦ Unity等に依存しない,一般的な
mp4 (H.264) 形式 8
©MIXI システムの要件 • キャプチャ実行時,直前の10秒程度を含む前後の動画を保存 • インゲームプレイ中,いつでもキャプチャ実行可能 • 保存した動画はSNS等へ投稿できる形式 ◦ Unity等に依存しない,一般的な
mp4 (H.264) 形式 9 これは ドライブレコーダーだ! 最近はゲーム機に搭載されていることも多い
©MIXI 基本の設計コンセプト 10
©MIXI 基本の設計コンセプト 11 15秒分の固定長の循環バッファを作り 常時録画・録音
©MIXI 基本の設計コンセプト 12 Android/iOSのコーデックAPIを利用
©MIXI ゲーム画面のキャプチャ
©MIXI ゲーム画面のキャプチャ 当初はRendererFeatureとして実装 RendererFeature: Universal Render Pipelineでカスタムの描画パスを挿入する仕組み 14 キャプチャ処理の実体 パラメータ定義
Rendererにパスを挿入するコンポーネント
©MIXI ゲーム画面のキャプチャ CameraCaptureBridgeを使うとデリゲートを登録するだけで簡単 にキャプチャ処理を挟むことができる 15 void Execute(RenderTargetIdentifier renderTargetIdentifier, CommandBuffer commandBuffer)
{ using (new ProfilingScope(commandBuffer, _profilingSampler)) { commandBuffer.Blit(renderTargetIdentifier, _captureOutputRenderTarget, _material); } } CameraCaptureBridge.AddCaptureAction(_targetCamera, Execute);
©MIXI mp4ファイルを作る
©MIXI コーデックAPI 連続画像を動画にエンコードするために,低レベルAPIを使う 17 iOS VTCompressionSession AVAssetWriter Android MediaCodec MediaMuxer
©MIXI コーデックAPI 連続画像を動画にエンコードするために,低レベルAPIを使う 18 iOS VTCompressionSession AVAssetWriter Android MediaCodec MediaMuxer
端末ごとの差異も少なく,それほどトラブルが発生しなかった
©MIXI コーデックAPI 連続画像を動画にエンコードするために,低レベルAPIを使う 19 iOS VTCompressionSession AVAssetWriter Android MediaCodec MediaMuxer
大変だった
©MIXI android.media.MediaCodec
©MIXI MediaCodecの入力データ • android.view.Surface ◦ MediaProjectionと相性が良いが今回の要件には合わない • android.media.Image ◦ ピクセルフォーマットを気にせずYUVの各Planeを扱えるが遅い
• java.nio.ByteBuffer ◦ 最速だがピクセルフォーマットを自分で組み立てる必要がある 21
©MIXI ByteBufferを使おう
©MIXI ByteBufferで入力するには… MediaCodecが直接扱える生データを入力する必要がある 以下のことを自分でやらなければならない • キャプチャした画像の色空間をRGBからYUVに変換 • YUVデータの色差成分をサブサンプリングしてYUV420に • YUV420データを適切なピクセルフォーマットにパック
23
©MIXI • キャプチャした画像の色空間をRGBからYUVに変換 • YUVデータの色差成分をサブサンプリングしてYUV420に • YUV420データを適切なピクセルフォーマットにパック 24
©MIXI YUV色空間 映像分野で標準的な色空間 輝度成分 Y と色差成分 U, V から成る ITU-R
BT.601 の係数を使って以下のように変換 25
©MIXI YUV色空間 キャプチャ時にYUV変換してRGB値としてRenderTextureに出力 U, V の範囲は –0.5~0.5 なので +0.5 している
26 YUVをRenderTextureのRGBとして出力 YUV変換 Capture Y U V
©MIXI • キャプチャした画像の色空間をRGBからYUVに変換 • YUVデータの色差成分をサブサンプリングしてYUV420に • YUV420データを適切なピクセルフォーマットにパック 27
©MIXI クロマサブサンプリング 色差成分を間引くことで圧縮 どのように間引くかによって YUV422, YUV420, YUV411 等の種類がある MediaCodecの入力フォーマットでは基本的にYUV420を使う 実際の間引きはピクセルフォーマット整形時に行う
28 U,V は 2×2 ピクセルあたり 1ピクセル分しか取らない https://developer.android.com/reference/android/media/MediaCodec
©MIXI • キャプチャした画像の色空間をRGBからYUVに変換 • YUVデータの色差成分をサブサンプリングしてYUV420に • YUV420データを適切なピクセルフォーマットにパック 29
©MIXI ピクセルフォーマット 同じ色空間のデータでもバイナリデータの配置方法は様々 RGBデータでも, という配置だけではなく,色ごとに分離した のような配置方法も場合によっては便利 30 Packed (Interleaved) Planar
©MIXI NV12 YUV420のピクセルフォーマットの一つ • Y-Plane と UV-Plane からなる Semi-planar 形式
• UV-Plane では UVUV... のように並ぶ 31 Packed UV Planar Y Semi-planar YUV420のピクセルフォーマットたち • NV12 YYYY...UVUV... • NV21 YYYY...VUVU... • I420 YYYY...UU...VV... • YV12 YYYY...VV...UU...
©MIXI MediaCodecへの入力まとめ 32
©MIXI 音声のキャプチャ レコーダー側は音声データを受け取るのみで,録音の具体的な方法 には踏み込まない ◦ Unity Audioの場合はOnAudioFilterReadを使う ◦ CRI ADXの場合はCriAtomExOutputAnalyzerを使う
ストブルはこちらの方法 音声はUnity C#側でリングバッファを用意して常時録音 mp4出力時にエンコーダへ音声データを書き込む 33
©MIXI mp4ファイル出力とシェア
©MIXI mp4ファイル書き出し I-フレーム(キーフレーム)が開始フレームになるように注意 補間 (P, B) フレームから開始すると動画の頭に乱れが生じる 最終的な動画の範囲はI-フレームを基準として決め,その時間に音声を合わせる 35 48,000
frames/sec 30 frames/sec
©MIXI OS機能のサポート • 他のアプリへファイル・テキストを共有 ◦ iOS: UIActivityViewController ◦ Android: Intent.createChooser
• 「アルバム」へファイルを保存 ◦ iOS: PHPhotoLibrary ◦ Android: MediaStore API 36 特にiOSのアプリ内データはユーザーが触れづらいので, 外側に取り出す仕組みが必要。 もちろん開発時のデータ確認でも必要だった。
©MIXI MediaStore API • Android 10 以降で Scoped Storage が有効
◦ 生パスではなくコンテンツURIを介してファイルアクセス ◦ WRITE_EXTERNAL_STORAGE 権限が不要 • Android 9 以前では直接 Movies フォルダへコピー ◦ WRITE_EXTERNAL_STORAGE 権限が必要 37
©MIXI システムのまとめ
©MIXI 動画エンコードパート 39
©MIXI 音声エンコードパート 40
©MIXI mp4ファイル出力パート 41
©MIXI ドキドキの多端末検証
©MIXI 様々な問題が発生しました
©MIXI デフォルトが NV12 ではない端末がある • Zenfone 8 ◦ I420: Y,
U, V の順の Planar 形式 • Y は正常 • U と V の取り方がかなり異なる ◦ 格子状に拡大したような状態になる 44
©MIXI アライメント問題 • 一部端末では横幅が16の倍数でなければならない ◦ Pixel 3a • パディングが必要 ◦
パディングが欠けているため斜めに歪む 45
©MIXI 続・アライメント問題 • さらに一部の端末では16の倍数でもだめなことがある ◦ Pixel 3a XL (≧ Android
12) • MediaCodec#getInputFormat の戻り値に含まれる stride, slice-height の値を使用する必要がある • stride, slice-height は含まれていないこともある ◦ その場合は16の倍数にアラインするのみとした 46
©MIXI slice-height の考慮 • Plane間にも適切なパディングが必要なことがある • 高さが適切でないと下部に緑色の領域が現れる事が多い ◦ U, V
が足りず途中で0になるため 47
©MIXI 入力バッファのサイズ getInputBufferで返されるByteBufferは stride, slice-height を考 慮した必要十分なサイズが確保されている 48
©MIXI 入力バッファのサイズ Y-Plane のサイズは 768 × 864 = 663,552 UV-Plane
のサイズは 768 × 848 / 2 = 325,632 ∴計 989,184 49 問題 width = 752, height = 848 で MediaCodec を初期化したところ, 入力フォーマットに stride = 768, slice-height = 864 という値が含まれ ていた。このとき,入力バッファのサイズは何バイトか。
©MIXI 入力バッファのサイズ Y-Plane のサイズは 768 × 864 = 663,552 UV-Plane
のサイズは 768 × 848 / 2 = 325,632 ∴計 989,184 50 問題 width = 752, height = 848 で MediaCodec を初期化したところ, 入力フォーマットに stride = 768, slice-height = 864 という値が含まれ ていた。このとき,入力バッファのサイズは何バイトか。 しかし実際には 989,169 15バイト少ない…
©MIXI 入力バッファのサイズ getInputBufferで返されるByteBufferは stride, slice-height を考 慮した必要十分なサイズが確保されている 足りない15バイトは 768 (stride)
– 752 (width) = 15 UV-Plane の最終行のパディングが不要 51
©MIXI stride, slice-height まとめ 52
©MIXI パフォーマンス問題 NV12データを Unity C# から Android Java へ渡す部分 53
byte[] frameData; AndroidJavaClass pluginClass; pluginClass.CallStatic("writeFrame", frameData); Unity 2019 vs 2020 で性能が2~3桁違う! 400,000 バイトの配列を渡してみると… Unity 2019 350 ms Unity 2020 0.5 ms (x700 faster!)
©MIXI パフォーマンス問題 Unity 2020.1.0 リリースノート https://unity.com/ja/releases/editor/whats-new/2020.1.0 54
©MIXI ということで
©MIXI 完成!!
©MIXI