Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@fuziki

[Unity]iOSでTextureを録画

はじめに

  • iOS 実機で、Unity の Texture と PCM を動画として録画して保存するアセットを作成しました
  • リポジトリはこちら↓

サンプルプロジェクト

  • サンプルプロジェクトの Unity のシーンは下の写真の通りでカメラが2個配置されています
  • 1つはメインカメラで、スクリーンに表示されます
  • もう1つは録画カメラ用カメラで、このカメラの映像と、本体のマイクの音声を .mov 形式で録画し、写真アプリに保存します スクリーンショット 2021-07-30 22.38.03.png

実際に動作している様子

導入方法

  • リポジトリExamples/UnityExample/Assets/Plugin/VideoCreator をコピーします

使い方

Setup

音声無しの mov ファイルを保存する

  • キャッシュパスは絶対パスの必要があります
  • コーデックは、"h264"と"hevcWithAlpha"をサポートしています
    • もし、アルファチャンネルの保存が必要な場合は、"hevcWithAlpha"を選択する必要があります
  • ビデオの幅と高さを指定します
string cachePath = "file://" + Application.temporaryCachePath + "/tmp.mov";
MediaCreator.InitAsMovWithAudio(cachePath, "h264", width, height);

音声有りの mov ファイルを保存する

  • 音声無しの場合に加えて、チャンネル数とサンプリング周波数を指定します
string cachePath = "file://" + Application.temporaryCachePath + "/tmp.mov";
MediaCreator.InitAsMovWithAudio(cachePath, "h264", texture.width, texture.height, 1, 48_000);

Live Photos を保存する

  • 通常の mov の設定に加えて、uuid を指定します
  • Live Photos に使用しない場合は、uuid は絶対に指定しないでください
string uuid = System.Guid.NewGuid().ToString();
string cachePath = "file://" + Application.temporaryCachePath + "/tmp.mov";
MediaCreator.InitAsMovWithAudio(cachePath, "h264", width, height, uuid);

音声を wav ファイルとして保存する

  • チャンネル数、サンプリング周波数、ビットデプスを指定します
string cachePath = "file://" + Application.temporaryCachePath + "/tmp.wav";
MediaCreator.InitAsWav(cachePath, 1, 48000, 32);

録画開始

  • 入力されるフレームの開始時刻を指定します
  • 単位はマイクロ秒です
long startTimeOffset = 0;
MediaCreator.Start(startTimeOffset);

Texture を書き込む

  • 書き込む Texture と時刻を渡します
  • こちらの時間もマイクロ秒で指定します
Texture texture = Get Texture;
long time = startTimeOffset + Elapsed time from Start;
MediaCreator.WriteVideo(texture, time);
  • ここではRenderTextureを作成し、Recording CameraのTargetTextureに設定しています
  • このRenderTextureをSerializeFieldのプロパティにも設定しています

スクリーンショット 2021-07-30 22.50.18.png

PCM を書き込む

  • float 配列と時刻を渡します
  • こちらの時間もマイクロ秒で指定します
float[] pcm = Get PCM float array;
long time = startTimeOffset + Elapsed time from Start;
MediaCreator.WriteAudio(pcm, time);
  • AudioSource を追加し、Microphone のクリップを設定して、playします。
var source = gameObject.AddComponent<AudioSource>();
var clip = Microphone.Start(null, true, 1, 48_000);
source.clip = clip;
source.loop = true;
while (Microphone.GetPosition(null) < 0) { }

source.Play();
  • OnAudioFilterRead で pcm の float 配列を取得し、書き込みます
void OnAudioFilterRead(float[] data, int channels)
{
    writeAudio(data, channels);

    for (int i = 0; i < data.Length; i++)
    {
        data[i] = 0;
    }
}

録画終了

  • 同期的に録画終了します
  • この処理は時間がかかる場合があります
MediaCreator.FinishSync();

動画をアルバムに保存する

  • MediaSaver に動画を保存した URL を渡して、アルバムに保存します
MediaSaver.SaveVideo(cachePath);

Live Photos をアルバムに保存する

  • Live Photos も MediaSaver を使って保存可能です
  • 動画の URL に加えて、サムネイルの画像と、動画を作成する時に使った uuid と同じ文字列を渡します
MediaSaver.SaveLivePhotos(texture, uuid, cachePath);

さいごに

  • Native Plugin を実装すると、Native の強力な機能を利用する事ができるようになります
  • アルファチャンネル付きで保存したり、Live Photos で保存する事で様々な応用ができそうです
  • windows/macOSで動画を保存するには→unity3d-jp/FrameCapturer
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What is going on with this article?