HoloLens2のファイルIOを確認する (その2 テキスト、画像、動画読み込み)
今回は前回の続きです。
xr-physics-work-etc.hatenablog.com
今回は、テキスト、画像、動画の読み込みを3種の方法で読み込んでみます。
読み込み方法は以下の通りです。
- テキスト:WUPの
FileIO.ReadTextAsync
でFileStorage
オブジェクトから読み込み - 画像:ファイルパスから
System.IO.File.ReadAllBytes
を用いたByte列読み込み - 動画:VideoPlayerコンポーネントでURL(ファイルパス)指定での読み込み
読み込み対象は、前回読み込めなかったMediaServerDevices
とRemovableDevices
を除いた14種としました。
1. 準備
準備として読み込み用のコンポーネントとGameObjectを用意します。
読み込み用コンポーネントでは、プルダウンメニューから読み込み対象を選択し、対象ディレクトリのテキスト、画像、動画を読み込み対象とする構成です。
- StorageReadCheck.cs
クリックで展開
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Video; using TMPro; #if WINDOWS_UWP using System; using Windows.Storage; #endif public class StorageReadCheck : MonoBehaviour { /// <summary> /// ストレージ情報クラス /// </summary> [SerializeField] private StorageFolderInfo storageFolderInfo; /// <summary> /// タイトル /// </summary> [SerializeField] private TextMeshPro title; /// <summary> /// ビデオプレイヤー /// </summary> [SerializeField] private VideoPlayer videoPlayer; /// <summary> /// 画像表示用MeshRenderer /// </summary> [SerializeField] private MeshRenderer imageMeshRenderer; /// <summary> /// 文章読み込み用テキスト /// </summary> [SerializeField] private TextMeshPro text; // Start is called before the first frame update void Start() { LoadFiles(); } // Update is called once per frame void Update() { } private void LoadFiles() { title.text = storageFolderInfo.targetStorageType.ToString(); LoadVideo(); LoadImage(); LoadText(); } private void LoadVideo() { #if WINDOWS_UWP videoPlayer.url = storageFolderInfo.GetStorageFile("test.mp4").Path; #endif } private void LoadImage() { Texture2D texture = new Texture2D(2, 2); #if WINDOWS_UWP texture.LoadImage(System.IO.File.ReadAllBytes(storageFolderInfo.GetStorageFile("test.png").Path)); #endif imageMeshRenderer.material.mainTexture = texture; } private void LoadText() { #if WINDOWS_UWP text.text = FileIO.ReadTextAsync(storageFolderInfo.GetStorageFile("test.txt")).GetAwaiter().GetResult(); #endif } } /// <summary> /// ストレージ情報クラス /// </summary> [System.Serializable] public class StorageFolderInfo { public TargetStorageType targetStorageType; #if WINDOWS_UWP public Dictionary<TargetStorageType, StorageFolder> targetStorageDict = new Dictionary<TargetStorageType, StorageFolder>(); #endif /// <summary> /// コンストラクタ /// ディクショナリ設定 /// </summary> public StorageFolderInfo() { #if WINDOWS_UWP targetStorageDict[TargetStorageType.AppCaptures] = KnownFolders.AppCaptures; targetStorageDict[TargetStorageType.CameraRoll] = KnownFolders.CameraRoll; targetStorageDict[TargetStorageType.DocumentsLibrary] = KnownFolders.DocumentsLibrary; targetStorageDict[TargetStorageType.MediaServerDevices] = KnownFolders.MediaServerDevices; targetStorageDict[TargetStorageType.MusicLibrary] = KnownFolders.MusicLibrary; targetStorageDict[TargetStorageType.Objects3D] = KnownFolders.Objects3D; targetStorageDict[TargetStorageType.PicturesLibrary] = KnownFolders.PicturesLibrary; targetStorageDict[TargetStorageType.Playlists] = KnownFolders.Playlists; targetStorageDict[TargetStorageType.RecordedCalls] = KnownFolders.RecordedCalls; targetStorageDict[TargetStorageType.RemovableDevices] = KnownFolders.RemovableDevices; targetStorageDict[TargetStorageType.SavedPictures] = KnownFolders.SavedPictures; targetStorageDict[TargetStorageType.VideosLibrary] = KnownFolders.VideosLibrary; targetStorageDict[TargetStorageType.LocalFolder] = ApplicationData.Current.LocalFolder; targetStorageDict[TargetStorageType.LocalCacheFolder] = ApplicationData.Current.LocalCacheFolder; targetStorageDict[TargetStorageType.RoamingFolder] = ApplicationData.Current.RoamingFolder; targetStorageDict[TargetStorageType.TemporaryFolder] = ApplicationData.Current.TemporaryFolder; #endif } #if WINDOWS_UWP /// <summary> /// フォルダ情報取得 /// </summary> /// <returns></returns> public StorageFolder GetStorageFolder() { return targetStorageDict[targetStorageType]; } /// <summary> /// ファイル情報取得 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public StorageFile GetStorageFile(string fileName) { return targetStorageDict[targetStorageType].GetFileAsync(fileName).GetAwaiter().GetResult(); } #endif } /// <summary> /// 対象ストレージタイプ /// </summary> public enum TargetStorageType { AppCaptures, CameraRoll, DocumentsLibrary, MediaServerDevices, MusicLibrary, Objects3D, PicturesLibrary, Playlists, RecordedCalls, RemovableDevices, SavedPictures, VideosLibrary, LocalFolder, LocalCacheFolder, RoamingFolder, TemporaryFolder, }
次に、表示するためのオブジェクトを用意します。
タイトルとテキスト読み込み用にTextMeshPro, 動画再生、画像表示用にQuadを空のGameObjectの配下に作成します。
Quadのマテリアルには、アプリ実行中にテクスチャを更新できるようにAssigned at Runtime
にチェックを入れておきます。
動画再生用のQuadにはVidoPlayerコンポーネントをアタッチします。
先ほど作成したStorageReadCheck
コンポーネントを親オブジェクトにアタッチして読み込み対象をプルダウンメニューから設定します。
当該オブジェクト(今回の場合FileLoadTest)をコピーし、それぞれ読み込みたい対象の読み込み対象をプルダウンメニューを変更して設定します。
最後に作成したFileLoadTest
を空オブジェクトの配下に変更し、GridObjectCollection
コンポーネントで整列させます。
2. 動作確認
各ディレクトリにtest.png, test.mp4, test.txtを配置してアプリを起動すると読み込み結果が確認できます。
※作成対象のディレクトリの対応は前回を対象xr-physics-work-etc.hatenablog.com
実際に読み込みを行った結果は以下の通りです。
テキスト、画像はどこからでも読み込みができ、パス指定でUnity標準コンポーネントに読み込ませている動画のみ、アプリ用ディレクトリ中のフォルダからのみ読み込みができる結果となりました。
StorageFolder | テキスト (UWP ReadTextAsync) | 画像 (バイト列) | 動画(ファイルパス読み込み) |
---|---|---|---|
KnownFolders.AppCaptures | ○ | ○ | × |
KnownFolders.CameraRoll | ○ | ○ | × |
KnownFolders.DocumentsLibrary | ○ | ○ | × |
KnownFolders.MusicLibrary | ○ | ○ | × |
KnownFolders.Objects3D | ○ | ○ | × |
KnownFolders.PicturesLibrary | ○ | ○ | × |
KnownFolders.Playlists | ○ | ○ | × |
KnownFolders.RecordedCalls | ○ | ○ | × |
KnownFolders.SavedPictures | ○ | ○ | × |
KnownFolders.VideosLibrary | ○ | ○ | × |
ApplicationData.Current.LocalFolder | ○ | ○ | ○ |
ApplicationData.Current.LocalCacheFolder | ○ | ○ | ○ |
ApplicationData.Current.RoamingFolder | ○ | ○ | ○ |
ApplicationData.Current.TemporaryFolder | ○ | ○ | ○ |
動画がアプリ固有ディレクトリ以外で読み込めない理由を確認してみます。
アプリ固有ディレクトリ中のTempState/UnityPlayer.log
を確認すると対象ディレクトリ中のファイル読み込み時に以下のメッセージが出力されていました。
WindowsMediaFoundation received empty file U:\USERS\[ユーザ名]\[対象ディレクトリ]\test.mp4
Unity標準のVideoPlayerの場合はファイルパス読み込みのため、UWPの一般フォルダの厳しい読み込み権限の問題で、ファイルの内容が読み込めないのかもしれません。
今のところ、動画読み込みにVideoPlayerを用いる場合はアプリ固有のディレクトリに動画ファイルを置くしかありませんが、バイト列で動画を読み込めるようなアセットがあれば、他のテキストや画像と同じようにKnownFoldersからも読み込めるかもしれません。