Dea Community,
I'm having trouble with a few aspects of my development, primarily in handling camera operations.
I am attempting to implement a camera preview function in Unity, however, I am consistently encountering a NullReferenceException and an InvalidParam Error during the process.
The issue manifests itself as a NullReferenceException
and an InvalidParam
error when interacting with the MLCamera API
.
The detailed error logs are as follows:
2023/05/28 13:28:06.782 26521 26542 Debug RefBase RefBase: Explicit destruction, weak count = 0 (in 0x71c8605ccd58)
2023/05/28 13:28:06.782 26521 26542 Warn RefBase CallStack::getCurrentInternal not linked, returning null
2023/05/28 13:28:06.782 26521 26542 Warn RefBase CallStack::logStackInternal not linked
2023/05/28 13:28:06.783 26521 26542 Error Unity NullReferenceException: Object reference not set to an instance of an object.
2023/05/28 13:28:06.783 26521 26542 Error Unity at MagicLeap.Examples.CameraCaptureExample.DisableImageCaptureObject () [0x00000] in <00000000000000000000000000000000>:0
2023/05/28 13:28:06.783 26521 26542 Error Unity at MagicLeap.Examples.CameraCaptureExample.OnApplicationPause (System.Boolean isPaused) [0x00000] in <00000000000000000000000000000000>:0
2023/05/28 13:28:06.783 26521 26542 Error Unity
2023/05/28 13:28:06.793 26521 26681 Info ml_camera_client Camonly OnAvailable CamId = 0
2023/05/28 13:28:09.214 26521 26698 Info ml_camera_client Camonly OnUnavailable CamId = 0
2023/05/28 13:28:09.215 26521 26542 Info Unity Camera device connected
2023/05/28 13:28:09.215 26521 26542 Info Unity MagicLeap.Examples.TestCameraRecording:ConnectCamera()
2023/05/28 13:28:09.215 26521 26542 Info Unity MagicLeap.Examples.<EnableMLCamera>d__19:MoveNext()
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
2023/05/28 13:28:09.215 26521 26542 Info Unity MagicLeap.Examples.TestCameraRecording:TryEnableMLCamera()
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine.XR.MagicLeap.<>c__DisplayClass20_0:<OnPermissionGranted>b__0()
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine.XR.MagicLeap.MLPermissions:OnPermissionGranted(String)
2023/05/28 13:28:09.215 26521 26542 Info Unity System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
2023/05/28 13:28:09.215 26521 26542 Info Unity System.Reflection.MethodBase:Invoke(Object, Object[])
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine.AndroidJavaProxy:Invoke(String, Object[])
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine.AndroidJavaProxy:Invoke(String, IntPtr)
2023/05/28 13:28:09.215 26521 26542 Info Unity UnityEngine._AndroidJNIHelper:InvokeJavaProxyMethod(AndroidJavaProxy, IntPtr, IntPtr)
2023/05/28 13:28:09.215 26521 26542 Info Unity
2023/05/28 13:28:09.216 26521 26542 Info Unity Camera device received stream caps
2023/05/28 13:28:09.216 26521 26542 Info Unity MagicLeap.Examples.TestCameraRecording:ConnectCamera()
2023/05/28 13:28:09.216 26521 26542 Info Unity MagicLeap.Examples.<EnableMLCamera>d__19:MoveNext()
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
2023/05/28 13:28:09.216 26521 26542 Info Unity MagicLeap.Examples.TestCameraRecording:TryEnableMLCamera()
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine.XR.MagicLeap.<>c__DisplayClass20_0:<OnPermissionGranted>b__0()
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine.XR.MagicLeap.MLPermissions:OnPermissionGranted(String)
2023/05/28 13:28:09.216 26521 26542 Info Unity System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
2023/05/28 13:28:09.216 26521 26542 Info Unity System.Reflection.MethodBase:Invoke(Object, Object[])
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine.AndroidJavaProxy:Invoke(String, Object[])
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine.AndroidJavaProxy:Invoke(String, IntPtr)
2023/05/28 13:28:09.216 26521 26542 Info Unity UnityEngine._AndroidJNIHelper:InvokeJavaProxyMethod(AndroidJavaProxy, IntPtr, IntPtr)
2023/05/28 13:28:09.216 26521 26542 Info Unity
2023/05/28 13:28:09.217 26521 26542 Error Unity NullReferenceException: Object reference not set to an instance of an object.
2023/05/28 13:28:09.217 26521 26542 Error Unity MagicLeap.Examples.TestCameraRecording:TryEnableMLCamera()
2023/05/28 13:28:09.217 26521 26542 Error Unity UnityEngine.XR.MagicLeap.<>c__DisplayClass20_0:<OnPermissionGranted>b__0()
2023/05/28 13:28:09.217 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLPermissions:OnPermissionGranted(String)
2023/05/28 13:28:09.217 26521 26542 Error Unity System.Reflection.RuntimeMethodInfo:Invoke(Object, BindingFlags, Binder, Object[], CultureInfo)
2023/05/28 13:28:09.217 26521 26542 Error Unity System.Reflection.MethodBase:Invoke(Object, Object[])
2023/05/28 13:28:09.217 26521 26542 Error Unity UnityEngine.AndroidJavaProxy:Invoke(String, Object[])
2023/05/28 13:28:09.217 26521 26542 Error Unity UnityEngine.AndroidJavaProxy:Invoke(String, IntPtr)
2023/05/28 13:28:09.217 26521 26542 Error Unity UnityEngine._AndroidJNIHelper:InvokeJavaProxyMethod(AndroidJavaProxy, IntPtr, IntPtr)
2023/05/28 13:28:09.217 26521 26542 Error Unity
2023/05/28 13:28:09.219 26521 26542 Info Input6DofFilter input_6dof_filter.cpp:92: Input6DofFilter was created
2023/05/28 13:28:09.220 26521 26542 Info Input6DofFilter input_6dof_filter.cpp:92: Input6DofFilter was created
2023/05/28 13:28:09.220 26521 26542 Info ml_input ml_input.cpp:1382: At application start, found controller device 257, type 1, registered as index 0
2023/05/28 13:28:09.221 26521 26542 Error Unity NullReferenceException: Object reference not set to an instance of an object.
2023/05/28 13:28:09.221 26521 26542 Error Unity
2023/05/28 13:28:09.221 26521 26542 Error Unity
2023/05/28 13:28:09.223 26521 26542 Error Unity Error: MLCameraConnect in the Magic Leap API failed. Reason: MLResult_InvalidParam
2023/05/28 13:28:09.223 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLResult:DidNativeCallSucceed(Code, String, Predicate`1, Boolean)
2023/05/28 13:28:09.223 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCameraBase:InternalConnect(ConnectContext)
2023/05/28 13:28:09.223 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCamera:Resume()
2023/05/28 13:28:09.223 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCamera:OnApplicationPause(Boolean)
2023/05/28 13:28:09.223 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLDevice:OnApplicationPause(Boolean)
2023/05/28 13:28:09.223 26521 26542 Error Unity
2023/05/28 13:28:09.223 26521 26542 Error Unity MLCamera.Connect failed connecting to the camera. Reason: InvalidParam
2023/05/28 13:28:09.224 26521 26542 Error Unity Error: MLCamera.Resume failed to connect camera. Reason: InvalidParam
2023/05/28 13:28:09.224 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCamera:Resume()
2023/05/28 13:28:09.224 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCamera:OnApplicationPause(Boolean)
2023/05/28 13:28:09.224 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLDevice:OnApplicationPause(Boolean)
2023/05/28 13:28:09.224 26521 26542 Error Unity
2023/05/28 13:28:09.224 26521 26542 Error Unity MLCamera.ApplicationPause failed to resume the camera. Reason: InvalidParam
2023/05/28 13:28:09.224 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLCamera:OnApplicationPause(Boolean)
2023/05/28 13:28:09.224 26521 26542 Error Unity UnityEngine.XR.MagicLeap.MLDevice:OnApplicationPause(Boolean)
2023/05/28 13:28:09.224 26521 26542 Error Unity
2023/05/28 13:28:09.227 26521 26538 Info ml_input ml_input.cpp:198: on_trigger, controller_id: 0, trigger event: Pull, trigger depth: 0.313726
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack Format:
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack samples_per_second=24000
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack channel_count=2
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack bits_per_sample=16
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack valid_bits_per_sample=16
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack sample_format=0
2023/05/28 13:28:09.248 26521 26699 Info AudioTrack channel_format=0
2023/05/28 13:28:09.249 26521 26699 Warn AudioTrack Use of stream types is deprecated for operations other than volume control
2023/05/28 13:28:09.249 26521 26699 Warn AudioTrack See the documentation of AudioTrack() for what to use instead with android.media.AudioAttributes to qualify your playback use case
2023/05/28 13:28:09.250 26521 26521 Verbose MediaRouter Selecting route: RouteInfo{ name=Phone, description=null, status=null, category=RouteCategory{ name=System types=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO groupable=false }, supportedTypes=ROUTE_TYPE_LIVE_AUDIO ROUTE_TYPE_LIVE_VIDEO , presentationDisplay=null }
2023/05/28 13:28:09.257 26521 26538 Info ml_input ml_input.cpp:198: on_trigger, controller_id: 0, trigger event: Pull, trigger depth: 0.145098
2023/05/28 13:28:09.287 26521 26538 Info ml_input ml_input.cpp:198: on_trigger, controller_id: 0, trigger event: Release, trigger depth: 0.000000
2023/05/28 13:28:17.257 26521 26542 Debug RefBase RefBase: Explicit destruction, weak count = 0 (in 0x71c8605ccd58)
2023/05/28 13:28:17.257 26521 26542 Warn RefBase CallStack::getCurrentInternal not linked, returning null
2023/05/28 13:28:17.257 26521 26542 Warn RefBase CallStack::logStackInternal not linked
2023/05/28 13:28:17.257 26521 26542 Error Unity NullReferenceException: Object reference not set to an instance of an object.
2023/05/28 13:28:17.257 26521 26542 Error Unity at MagicLeap.Examples.CameraCaptureExample.DisableImageCaptureObject () [0x00000] in <00000000000000000000000000000000>:0
2023/05/28 13:28:17.257 26521 26542 Error Unity at MagicLeap.Examples.CameraCaptureExample.OnApplicationPause (System.Boolean isPaused) [0x00000] in <00000000000000000000000000000000>:0
2023/05/28 13:28:17.257 26521 26542 Error Unity
2023/05/28 13:28:17.287 26521 26731 Info ml_camera_client Camonly OnAvailable CamId = 0
2023/05/28 13:28:18.745 26521 26521 Info Process Sending signal. PID: 26521 SIG: 9
Some background on my project: I am working on a camera capture example, where I aim to handle
the camera's availability, connect, enable, preview it on canvas background and finally disable it upon pausing the application. I suspect the issues come from the DisableImageCaptureObject()
method within the CameraCaptureExample
class, and TryEnableMLCamera()
method within the TestCameraRecording
class as these are where the exceptions are thrown according to the stack trace.
I'm also getting errors when trying to use MLCamera.Connect
and MLCamera.Resume
methods, with an InvalidParam
error. This issue is not clear to me as I believe I'm providing all the necessary parameters.
Here is the current version of the Script:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using MagicLeap.Core;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.MagicLeap;
namespace MagicLeap.Examples
{
/// <summary>
/// This class handles video recording and image capturing based on controller
/// input.
/// </summary>
///
public class TestCameraRecording : MonoBehaviour
{
private MLCamera.CaptureFrameRate FrameRate ;
private MLCamera.OutputFormat OutputFormat ;
private MLCamera captureCamera;
private bool isCapturingVideo = false;
[SerializeField, Tooltip("Reference to media player behavior used in camera capture playback")]
private MLMediaPlayerBehavior mediaPlayerBehavior;
private readonly CameraRecorder cameraRecorder = new CameraRecorder();
private const string validFileFormat = ".mp4";
private bool isCapturingPreview = false;
private bool RecordToFile = true;
private string recordedFilePath;
private MLCamera.CaptureType CaptureType = MLCamera.CaptureType.Video;
private List<MLCamera.StreamCapability> streamCapabilities;
[SerializeField, Tooltip("Button that starts the Capture")]
private Button captureButton;
private readonly MLPermissions.Callbacks permissionCallbacks = new MLPermissions.Callbacks();
private bool cameraDeviceAvailable;
[SerializeField, Tooltip("Refrence to the Raw Video Capture Visualizer gameobject for YUV frames")]
private CameraCaptureVisualizer cameraCaptureVisualizer = null;
private void Awake()
{
permissionCallbacks.OnPermissionGranted += OnPermissionGranted;
permissionCallbacks.OnPermissionDenied += OnPermissionDenied;
permissionCallbacks.OnPermissionDeniedAndDontAskAgain += OnPermissionDenied;
//connectionFlagDropdown.AddOptions(
// MLCamera.ConnectFlag.CamOnly,
// MLCamera.ConnectFlag.MR,
// MLCamera.ConnectFlag.VirtualOnly);
//captureButton.onClick.AddListener(OnCaptureButtonClicked);
//connectButton.onClick.AddListener(ConnectCamera);
//disconnectButton.onClick.AddListener(DisconnectCamera);
//connectionFlagDropdown.onValueChanged.AddListener(v => RefreshUI());
//streamCapabilitiesDropdown.onValueChanged.AddListener(v => RefreshUI());
//qualityDropDown.onValueChanged.AddListener(v => RefreshUI());
//captureTypeDropDown.onValueChanged.AddListener(v => RefreshUI());
//frameRateDropDown.onValueChanged.AddListener(v => RefreshUI());
//RefreshUI();
}
// Start is called before the first frame update
private void Start()
{
Debug.Log("Start");
MLPermissions.RequestPermission(MLPermission.Camera, permissionCallbacks);
MLPermissions.RequestPermission(MLPermission.RecordAudio, permissionCallbacks);
TryEnableMLCamera();
}
private void TryEnableMLCamera()
{
if (!MLPermissions.CheckPermission(MLPermission.Camera).IsOk)
return;
StartCoroutine(EnableMLCamera());
}
private IEnumerator EnableMLCamera()
{
while (!cameraDeviceAvailable)
{
MLResult result =
MLCamera.GetDeviceAvailabilityStatus(MLCamera.Identifier.Main, out cameraDeviceAvailable);
if (!(result.IsOk && cameraDeviceAvailable))
{
// Wait until camera device is available
yield return new WaitForSeconds(1.0f);
}
else
{
ConnectCamera();
// Camera device is available, start video capture here
}
}
Debug.Log("Camera device available");
}
// Update is called once per frame
void Update()
{
}
private void OnPermissionDenied(string permission)
{
if (permission == MLPermission.Camera)
{
MLPluginLog.Error($"{permission} denied, example won't function.");
}
else if (permission == MLPermission.RecordAudio)
{
MLPluginLog.Error($"{permission} denied, audio wont be recorded in the file.");
}
//RefreshUI();
}
private void OnPermissionGranted(string permission)
{
MLPluginLog.Debug($"Granted {permission}.");
TryEnableMLCamera();
//RefreshUI();
}
private void StartVideoCapture()
{
// recordedFilePath = string.Empty;
// skipFrame = false;
var result = MLPermissions.CheckPermission(MLPermission.Camera);
MLResult.DidNativeCallSucceed(result.Result, nameof(MLPermissions.RequestPermission));
if (!result.IsOk)
{
Debug.LogError($"{MLPermission.Camera} permission denied. Video will not be recorded.");
return;
}
if (RecordToFile)
StartRecording();
else
StartPreview();
}
private void StartRecording()
{
// media player not supported in Magic Leap App Simulator
#if !UNITY_EDITOR
mediaPlayerBehavior.MediaPlayer.OnPrepared += MediaPlayerOnOnPrepared;
mediaPlayerBehavior.MediaPlayer.OnCompletion += MediaPlayerOnCompletion;
#endif
string fileName = DateTime.Now.ToString("MM_dd_yyyy__HH_mm_ss") + validFileFormat;
recordedFilePath = System.IO.Path.Combine(Application.persistentDataPath, fileName);
CameraRecorderConfig config = CameraRecorderConfig.CreateDefault();
config.Width = streamCapabilities[0].Width;
config.Height = streamCapabilities[0].Height;
config.FrameRate = MapFrameRate(MLCamera.CaptureFrameRate._60FPS);
cameraRecorder.StartRecording(recordedFilePath, config);
int MapFrameRate(MLCamera.CaptureFrameRate frameRate)
{
switch (frameRate)
{
case MLCamera.CaptureFrameRate.None: return 0;
case MLCamera.CaptureFrameRate._15FPS: return 15;
case MLCamera.CaptureFrameRate._30FPS: return 30;
case MLCamera.CaptureFrameRate._60FPS: return 60;
default: return 0;
}
}
MLCamera.CaptureConfig captureConfig = new MLCamera.CaptureConfig();
captureConfig.CaptureFrameRate = FrameRate;
captureConfig.StreamConfigs = new MLCamera.CaptureStreamConfig[1];
captureConfig.StreamConfigs[0] = MLCamera.CaptureStreamConfig.Create(streamCapabilities[0], OutputFormat);
captureConfig.StreamConfigs[0].Surface = cameraRecorder.MediaRecorder.InputSurface;
MLResult result = captureCamera.PrepareCapture(captureConfig, out MLCamera.Metadata _);
if (MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.PrepareCapture)))
{
captureCamera.PreCaptureAEAWB();
if (CaptureType == MLCamera.CaptureType.Video)
{
result = captureCamera.CaptureVideoStart();
isCapturingVideo = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CaptureVideoStart));
if (isCapturingVideo)
{
cameraCaptureVisualizer.DisplayCapture(captureConfig.StreamConfigs[0].OutputFormat, RecordToFile);
}
}
if (CaptureType == MLCamera.CaptureType.Preview)
{
result = captureCamera.CapturePreviewStart();
isCapturingPreview = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CapturePreviewStart));
if (isCapturingPreview)
{
cameraCaptureVisualizer.DisplayPreviewCapture(captureCamera.PreviewTexture, RecordToFile);
}
}
}
}
private void StartPreview()
{
MLCamera.CaptureConfig captureConfig = new MLCamera.CaptureConfig();
captureConfig.CaptureFrameRate = MLCamera.CaptureFrameRate._60FPS;
captureConfig.StreamConfigs = new MLCamera.CaptureStreamConfig[1];
captureConfig.StreamConfigs[0] =
MLCamera.CaptureStreamConfig.Create(streamCapabilities[0], OutputFormat);
MLResult result = captureCamera.PrepareCapture(captureConfig, out MLCamera.Metadata _);
if (MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.PrepareCapture)))
{
captureCamera.PreCaptureAEAWB();
// if (CaptureType == MLCamera.CaptureType.Video)
// {
// result = captureCamera.CaptureVideoStart();
// isCapturingVideo = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CaptureVideoStart));
// if (isCapturingVideo)
// {
// cameraCaptureVisualizer.DisplayCapture(captureConfig.StreamConfigs[0].OutputFormat, true);
// }
// }
// if (CaptureType == MLCamera.CaptureType.Preview)
// {
result = captureCamera.CapturePreviewStart();
isCapturingPreview = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CapturePreviewStart));
Debug.LogError($"isCapturingPreview {isCapturingPreview} ");
// if (isCapturingPreview)
// {
cameraCaptureVisualizer.DisplayPreviewCapture(captureCamera.PreviewTexture, true);
// }
// }
}
}
private void ConnectCamera()
{
MLCamera.ConnectContext context = MLCamera.ConnectContext.Create();
context.Flags = MLCamera.ConnectFlag.CamOnly;
context.EnableVideoStabilization = true;
if (context.Flags != MLCamera.ConnectFlag.CamOnly)
{
context.MixedRealityConnectInfo = MLCamera.MRConnectInfo.Create();
context.MixedRealityConnectInfo.MRQuality = MLCamera.MRQuality._960x720;
context.MixedRealityConnectInfo.MRBlendType = MLCamera.MRBlendType.Additive;
context.MixedRealityConnectInfo.FrameRate = MLCamera.CaptureFrameRate._60FPS;
}
captureCamera = MLCamera.CreateAndConnect(context);
if (captureCamera != null)
{
Debug.Log("Camera device connected");
if (GetImageStreamCapabilities())
{
Debug.Log("Camera device received stream caps");
// captureCamera.OnRawVideoFrameAvailable += OnCaptureRawVideoFrameAvailable;
// captureCamera.OnRawImageAvailable += OnCaptureRawImageComplete;
StartVideoCapture();
}
}
}
private bool GetImageStreamCapabilities()
{
var result =
captureCamera.GetStreamCapabilities(out MLCamera.StreamCapabilitiesInfo[] streamCapabilitiesInfo);
if (!result.IsOk)
{
Debug.Log("Could not get Stream capabilities Info.");
return false;
}
streamCapabilities = new List<MLCamera.StreamCapability>();
for (int i = 0; i < streamCapabilitiesInfo.Length; i++)
{
foreach (var streamCap in streamCapabilitiesInfo[i].StreamCapabilities)
{
streamCapabilities.Add(streamCap);
}
}
return streamCapabilities.Count > 0;
}
private void MediaPlayerOnOnPrepared(MLMedia.Player mediaplayer)
{
// media player not supported in Magic Leap App Simulator
#if !UNITY_EDITOR
mediaPlayerBehavior.Play();
#endif
}
private void MediaPlayerOnCompletion(MLMedia.Player mediaplayer)
{
// media player not supported in Magic Leap App Simulator
#if !UNITY_EDITOR
mediaPlayerBehavior.StopMLMediaPlayer();
#endif
mediaPlayerBehavior.gameObject.SetActive(false);
mediaPlayerBehavior.Reset();
}
}
}
Could anyone provide insights or solutions on these issues? Any help would be much appreciated!
Thanks in advance,
Muhammad Usman Bashir