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.3k
「騒ゲーハイライト」について【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
980
Other Decks in Technology
See All in Technology
設計を積み重ねてシステムを刷新する
sansantech
PRO
0
150
Potential EM 制度を始めた理由、そして2年後にやめた理由 - EMConf JP 2025
hoyo
2
2.3k
IAMポリシーのAllow/Denyについて、改めて理解する
smt7174
2
190
CDKのコードを書く環境を作りました with Amazon Q
nobuhitomorioka
1
160
データマネジメントのトレードオフに立ち向かう
ikkimiyazaki
6
1.2k
PHPカンファレンス名古屋-テックリードの経験から学んだ設計の教訓
hayatokudou
2
540
Iceberg Meetup Japan #1 : Iceberg and Databricks
databricksjapan
0
310
「正しく」失敗できる チームの作り方 〜リアルな事例から紐解く失敗を恐れない組織とは〜 / A team that can fail correctly
i35_267
4
780
【詳説】コンテンツ配信 システムの複数機能 基盤への拡張
hatena
0
210
EDRの検知の仕組みと検知回避について
chayakonanaika
11
4.5k
1行のコードから社会課題の解決へ: EMの探究、事業・技術・組織を紡ぐ実践知 / EM Conf 2025
9ma3r
8
3.3k
What's new in Go 1.24?
ciarana
1
100
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
640
[RailsConf 2023] Rails as a piece of cake
palkan
53
5.3k
Fireside Chat
paigeccino
34
3.2k
The Cost Of JavaScript in 2023
addyosmani
47
7.4k
Agile that works and the tools we love
rasmusluckow
328
21k
Thoughts on Productivity
jonyablonski
69
4.5k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
4
360
How GitHub (no longer) Works
holman
314
140k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.3k
Speed Design
sergeychernyshev
27
810
Rails Girls Zürich Keynote
gr2m
94
13k
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