これまでAndroid、Wondows PCでWebCamTextureを使って映像を出力する方法やGetPixcel32()でメモリリークを防ぐ方法などをまとめてきました。
今回、iOSのアプリでWebCamTextureを使ってみたところ、また新たな発見がありましたので、上記記事に追加という形でまとめておこうと思います。
iOSで正しくWebCamTextureを使いこなす。
カメラの権限
iOSでもAndroid同様にカメラの使用許可を要求する必要があります。その処理がAndroidとは異なり、以下のようなロジックになります。
IEnumerator Start()
{
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
if (Application.HasUserAuthorization(UserAuthorization.WebCam)) {
// UnityのWebCamTextureで処理
}
}
Androidで使用していたPermission.Cameraは使用せず、UserAuthorization.WebCamを使用する点に注意してください。また、Xcodeでも以下の通り、info.plistにPrivacy – Camera Usage Description設定が必要になります。

カメラの起動
Androidでは特に気にしていなかったカメラの起動待ちですが、iOSではすぐには起動してこないようです。というのも、WebCamTextureインスタンスのPlay()による起動直後にwidthパラメータを参照したところ、requestedWidthとは全く異なる値(16)が読み出せてしまいました。時間がたつと、requestedWidthでリクエストした値に変化することから、起動していないと判断しました。
これには、コルーチンでカメラを起動させることで対応しました。コルーチンとはStartCoroutine()で実行できるタスクのようなものです。コルーチンは処理を途中で抜けることができ、処理の続きを次のフレームや指定時間後に処理できるというものです。
以下にカメラ起動のコードを示します。
// カメラを起動させる
public void StartCamera()
{
// 処理はコルーチンで実行する
StartCoroutine(_startCamera());
}
IEnumerator _startCamera()
{
// 指定カメラを起動させる
webCam = new WebCamTexture(WebCamTexture.devices[0].name, 640, 480);
// RawImageのテクスチャにWebCamTextureのインスタンスを設定
RawImage.texture = webCam;
// カメラ起動
webCam.Play();
while (webCam.width != webCam.requestedWidth)
{
// widthが指定したものになっていない場合は処理を抜けて次のフレームで再開
yield return null;
}
yield break;
}
_startCameraがコルーチンで処理するためにIEnumeratorで定義されているのに注意してください。yield return nullはここは一旦引いて、次のフレームでまた続きをやるための記述です。コルーチンはyield breakで終了します。
WebCamTextureのwidthを参照して表示を制御している場合、きちんと起動を待たないと、表示がおかしいことになるかと思います。
カメラの表示
カメラの表示はAndroidと同じなのですが、以前の記事でvideoVerticallyMirroredの取り扱いを間違っているところがあったので、ここで訂正させていただきます。カメラの表示を正しい向きで取り込むためのコードは以下になります。
if (webCam.videoVerticallyMirrored)
{
//左右反転しているのを戻す
Vector3 scaletmp = RawImage.GetComponent<RectTransform>().localScale;
scaletmp.y = -1;
RawImage.GetComponent<RectTransform>().localScale = scaletmp;
}
// 起動させて初めてvideoRotationAngle、width、heightに値が入り、
// アスペクト比、何度回転させれば正しく表示されるかがわかる
// 表示するRawImageを回転させる
Vector3 angles = RawImage.GetComponent<RectTransform>().eulerAngles;
angles.z = -webCam.videoRotationAngle;
RawImage.GetComponent<RectTransform>().eulerAngles = angles;
// widthはx、heightはyでサイズ調整
// 全体を表示させるように、大きい方のサイズを表示枠に合わせる
float scaler;
Vector2 sizetmp = RawImage.GetComponent<RectTransform>().sizeDelta;
if (webCam.width > webCam.height)
{
scaler = sizetmp.x / webCam.width;
}
else
{
scaler = sizetmp.y / webCam.height;
}
// サイズ調整
sizetmp.x = webCam.width * scaler;
sizetmp.y = webCam.height * scaler;
// 表示領域サイズ設定
RawImage.GetComponent<RectTransform>().sizeDelta = sizetmp;
if (WebCamTexture.devices[0].isFrontFacing ) {
// Face Cameraの場合は反転表示させる回転の向きによって、どの軸で回転させるかが異なる
Vector3 scaletmp = RawImage.GetComponent<RectTransform>().localScale;
if ((webCam.videoRotationAngle == 90) || (webCam.videoRotationAngle == 270))
{
scaletmp.y *= -1;
} else
{
scaletmp.x *= -1;
}
RawImage.GetComponent<RectTransform>().localScale = scaletmp;
}
以前はisFrontFacingがTrueでvideoVerticallyMirroredもTrueだったら、反転させる必要ないと思っていたのですが、videoVerticallyMirroredは回転する前の映像が反転しているかどうかなので、まず最初に反転なしの正しい映像に戻してやります。
その上でisFrontFacingがTrueの時は回転後の正しい軸で反転させてあげます。Androidの時はvideoVerticallyMirroredがTrueなデバイスに当たっていなかったので、正しく表示できていましたが、iOSはTrueで来たので気づくことができました。
まとめ
iOS、Android共にNativeライブラリを用いることなく、カメラの映像を正しく表示させることができました。WebCamTextureのパラメータは実際に触ってみないとわかならいものが多かったり、カメラの起動待ちなどふるまいも動かしてみないとわからないものが多いと感じました。
iOSやAndroidで実際にカメラを動かしてWebCamTextureやNativeのパラメータを確認するアプリをリリースしています。手軽に手持ちのデバイスでカメラの動きやパラメータを確認できるアプリになっています。ご参考まで。


コメント
[…] 【Unity】WebCamTextureでiOSのカメラを使いこなす これまでAndroid、Wondows PCでWe… […]