Hello everyone.

The Mixed Reality Forums here are no longer being used or maintained.

There are a few other places we would like to direct you to for support, both from Microsoft and from the community.

The first way we want to connect with you is our mixed reality developer program, which you can sign up for at https://aka.ms/IWantMR.

For technical questions, please use Stack Overflow, and tag your questions using either hololens or windows-mixed-reality.

If you want to join in discussions, please do so in the HoloDevelopers Slack, which you can join by going to https://aka.ms/holodevelopers, or in our Microsoft Tech Communities forums at https://techcommunity.microsoft.com/t5/mixed-reality/ct-p/MicrosoftMixedReality.

And always feel free to hit us up on Twitter @MxdRealityDev.
Options

[Unity] TakePhotoAsync only working once

Hello,

I have a very strange behavior with the locatable camera API on Hololens.
When I trigger capture.TakePhotoAsync, the callback is only called once. On the second time I trigger it, the callback is never called and the opened thread never seems to be closed, it looks like TakePhotoAsync keeps on running. The debugger even failed to close :

However it is working perfectly in the editor.

Here is my code :

using System;
using System.Collections;
using System.Linq;
using HoloToolkit.Unity.InputModule;
using HoloToolkit.Unity;
using UnityEngine;
using UnityEngine.XR.WSA.WebCam;

/// <summary>
/// Manages taking and saving photos.
/// </summary>
public class PhotoManager : Singleton<PhotoManager>
{
    /// <summary>
    /// Actual camera instance.
    /// </summary>
    private PhotoCapture capture;

    /// <summary>
    /// True, if the camera is ready to take photos.
    /// </summary>
    public bool isReady { get; private set; }
    public Resolution resolution { get; private set; }

    #region EVENTS
    public event Action<bool> OnCaptureReady;
    public event Action OnCaptureOff;
    #endregion

    private Coroutine launchedStartCapture;
    private CameraParameters cameraParameters;

    protected override void Awake()
    {
        base.Awake();
        isReady = false;
        // This resolution guarantee that it will have holograms in the whole picture
        resolution = PhotoCapture.SupportedResolutions.OrderByDescending(res => res.width * res.height).ElementAt(1);
        cameraParameters = new CameraParameters(WebCamMode.PhotoMode)
        {
            hologramOpacity = 1.0f,
            cameraResolutionWidth = resolution.width,
            cameraResolutionHeight = resolution.height,
            pixelFormat = CapturePixelFormat.BGRA32
        };
    }

    private void OnDisable()
    {
        StopCapture();
    }

    public void StartCapture(Action<bool> callback = null)
    {
        if (launchedStartCapture != null)
        {
            StopCoroutine(launchedStartCapture);
        }

        launchedStartCapture = StartCoroutine(StartCaptureCoroutine(callback));
    }

    private IEnumerator StartCaptureCoroutine(Action<bool> callback = null)
    {
        bool stopped = false;
        StopCapture(res => stopped = true);

        yield return new WaitUntil(() => stopped);

        if (WebCam.Mode != WebCamMode.None)
        {
            Debug.LogErrorFormat(this, "Can't activate capture, webcam is already in mode {0}", WebCam.Mode);
            if (callback != null) callback(false);
            yield break;
        }

        if (ExakisTools.Utils.HoloLensHelpers.IsStreaming())
        {
            Debug.LogErrorFormat(this, "Can't activate capture, application is in currently streaming");
            if (callback != null) callback(false);
            yield break;
        }

        PhotoCapture.CreateAsync(true, captureObject =>
        {
            capture = captureObject;

            capture.StartPhotoModeAsync(cameraParameters, res => this.OnPhotoModeStarted(res, callback));
        });
    }

    private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result, Action<bool> callback)
    {
        isReady = result.success;
        if (OnCaptureReady != null) OnCaptureReady(isReady);
        if (isReady)
        {
            callback?.Invoke(true);
            // [Quick Fix] Hologramms are not shown on first picture
            // capture.TakePhotoAsync((photoResult, photoCaptureFrame) =>
            // {
            //     photoCaptureFrame.Dispose();
            //     photoCaptureFrame = null;
            //     callback?.Invoke(true);
            // });
            Debug.Log("Camera ready");
        }
        else
        {
            Debug.LogErrorFormat(this, "Failed to activate capture, if you are streaming, please remove it, reason : {0}", result.resultType);
        }
    }

    /// <summary>
    /// Take a picture if the capture is on
    /// </summary>
    /// <param name="photoTaken"> Callback when the picture is taken </param>
    public void TakePhoto(Action<Texture2D> photoTaken = null)
    {
        if (isReady)
        {
            UnityEngine.XR.WSA.HolographicSettings.SetFocusPointForFrame(CameraCache.Main.transform.TransformPoint(0, 0, 1f), -CameraCache.Main.transform.forward);
            capture.TakePhotoAsync((result, photoCaptureFrame) =>
            {
                if (result.success)
                {
                    Texture2D targetTexture = new Texture2D(resolution.width, resolution.height, TextureFormat.BGRA32, false);
                    photoCaptureFrame.UploadImageDataToTexture(targetTexture);
                    photoCaptureFrame.Dispose();
                    photoTaken.Invoke(targetTexture);
                }
                else
                {
                    Debug.LogErrorFormat("Failed to take photo {0}", result.hResult);
                }
            });
        }
        else
        {
            Debug.LogWarning("The camera is not yet ready.");
        }
    }

    /// <summary>
    /// Stop the photo mode.
    /// </summary>
    /// <param name="callback"> return true if the capture has been stopped</param>
    public void StopCapture(Action<bool> callback = null)
    {
        if (capture != null)
        {
            capture.StopPhotoModeAsync(result =>
            {
                capture.Dispose();
                capture = null;
                isReady = false;
                Debug.Log("Camera off");
                if (OnCaptureOff != null) OnCaptureOff();
                if (callback != null) callback(true);
            });
        }
        else
        {
            if (callback != null) callback(false);
        }
    }
}

I am aware there are a lot of problems with photo capture on HoloLens by now but I didn't found anything about this behavior at the moment.

If we have to wait to have it fixed, is there a workaround ? Like using the UWP API maybe ?

Here is my configuration:
Unity 2017.4.11f1 LTS
Scripting runtime : .NET 4.6
Windows SDK: 10.0.17134.0
Hololens OS: RS4 update

Sign In or Register to comment.