Give us as much detail as possible regarding the issue you're experiencing:
Unity Editor version : 2022.3.48f1
ML2 OS version : 1.11.0
Unity SDK version : 2.5.0
Host OS : (Windows/MacOS): Winow 11
Hi, I am saving MP4 video file using CameraRecorder with start and stop function. The first recording successfully works. The issue is that when i try second recording after first recording, when I see the recorded file in the real-time using ML hub, the file is created, but not finished, while the file size remaining around 1MB, and very slowly increase, but not complete at all.
I hope my code could record successfully every time when I call the start and the stop function multiple times. Here is my code.
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
{
public class TestCameraRecording_MainCamera : MonoBehaviour
{
private MLCamera.CaptureFrameRate FrameRate = MLCamera.CaptureFrameRate._30FPS;
private MLCamera.OutputFormat OutputFormat = MLCamera.OutputFormat.RGBA_8888;
private MLCamera captureCamera;
private bool isCapturingVideo = false;
private readonly CameraRecorder cameraRecorder = new CameraRecorder();
private const string validFileFormat = ".mp4";
private string recordedFilePath;
private MLCamera.CaptureType CaptureType = MLCamera.CaptureType.Video;
private List<MLCamera.StreamCapability> streamCapabilities;
private readonly MLPermissions.Callbacks permissionCallbacks = new MLPermissions.Callbacks();
private bool cameraDeviceAvailable;
private void Awake()
{
permissionCallbacks.OnPermissionGranted += OnPermissionGranted;
permissionCallbacks.OnPermissionDenied += OnPermissionDenied;
permissionCallbacks.OnPermissionDeniedAndDontAskAgain += OnPermissionDenied;
}
private void Start()
{
Debug.Log("Start");
MLPermissions.RequestPermission(MLPermission.Camera, permissionCallbacks);
MLPermissions.RequestPermission(MLPermission.RecordAudio, permissionCallbacks);
}
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(0.5f);
}
else
{
ConnectCamera();
}
}
Debug.Log("Camera device available");
}
private void Update()
{
// Debug.Log($"Frame Number");
}
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.");
}
}
private void OnPermissionGranted(string permission)
{
MLPluginLog.Debug($"Granted {permission}.");
// TryEnableMLCamera();
}
public void StartVideoCapture()
{
TryEnableMLCamera();
var result = MLPermissions.CheckPermission(MLPermission.Camera);
MLResult.DidNativeCallSucceed(result.Result, nameof(MLPermissions.RequestPermission));
Debug.Log($"CLPermissions.CheckPermission {result}");
if (!result.IsOk)
{
Debug.LogError($"{MLPermission.Camera} permission denied. Video will not be recorded.");
return;
}
StartRecording();
}
private void StartRecording()
{
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._30FPS);
cameraRecorder.StartRecording(recordedFilePath, config);
// Subscribe to the OnInfo event
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();
// Debug.Log($"Video recording started successfully. at {Time.time}");
SharedInfomanager.Instance.SetStartrecordingtime(Time.time);
isCapturingVideo = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CaptureVideoStart));
if (isCapturingVideo)
{
Debug.Log($"Video recording started successfully. at {Time.time}");
}
}
}
}
public void StopRecording()
{
if (!isCapturingVideo)
{
Debug.LogWarning("No recording is in progress to stop.");
return;
}
captureCamera.CaptureVideoStop();
MLResult result = cameraRecorder.EndRecording();
if (!result.IsOk)
{
Debug.LogError($"Failed to stop recording: {result}");
recordedFilePath = string.Empty;
}
else
{
Debug.Log($"Recording saved at path: {recordedFilePath}");
}
isCapturingVideo = false;
// Disconnect and disable the camera
DisconnectCamera();
}
private void ConnectCamera()
{
MLCamera.ConnectContext context = MLCamera.ConnectContext.Create();
context.Flags = MLCamera.ConnectFlag.MR;
context.EnableVideoStabilization = true;
if (context.Flags != MLCamera.ConnectFlag.CamOnly)
{
context.MixedRealityConnectInfo = MLCamera.MRConnectInfo.Create();
context.MixedRealityConnectInfo.MRQuality = MLCamera.MRQuality._648x720;
context.MixedRealityConnectInfo.MRBlendType = MLCamera.MRBlendType.Additive;
context.MixedRealityConnectInfo.FrameRate = MLCamera.CaptureFrameRate._30FPS;
}
captureCamera = MLCamera.CreateAndConnect(context);
if (captureCamera != null)
{
Debug.Log("Camera device connected");
if (GetImageStreamCapabilities())
{
Debug.Log("Camera stream capabilities received.");
}
}
}
private void DisconnectCamera()
{
if (captureCamera != null)
{
captureCamera.Disconnect();
// MLCamera.Uninitialize();
captureCamera = null;
Debug.Log("Camera disconnected");
}
}
private bool GetImageStreamCapabilities()
{
var result =
captureCamera.GetStreamCapabilities(out MLCamera.StreamCapabilitiesInfo[] streamCapabilitiesInfo);
if (!result.IsOk)
{
Debug.LogError("Failed to get stream capabilities info.");
return false;
}
streamCapabilities = new List<MLCamera.StreamCapability>();
foreach (var info in streamCapabilitiesInfo)
{
streamCapabilities.AddRange(info.StreamCapabilities);
}
return streamCapabilities.Count > 0;
}
}
}
And this is my CameraRecorderConfig 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
{
public class TestCameraRecording_MainCamera : MonoBehaviour
{
private MLCamera.CaptureFrameRate FrameRate = MLCamera.CaptureFrameRate._30FPS;
private MLCamera.OutputFormat OutputFormat = MLCamera.OutputFormat.RGBA_8888;
private MLCamera captureCamera;
private bool isCapturingVideo = false;
private readonly CameraRecorder cameraRecorder = new CameraRecorder();
private const string validFileFormat = ".mp4";
private string recordedFilePath;
private MLCamera.CaptureType CaptureType = MLCamera.CaptureType.Video;
private List<MLCamera.StreamCapability> streamCapabilities;
private readonly MLPermissions.Callbacks permissionCallbacks = new MLPermissions.Callbacks();
private bool cameraDeviceAvailable;
private void Awake()
{
permissionCallbacks.OnPermissionGranted += OnPermissionGranted;
permissionCallbacks.OnPermissionDenied += OnPermissionDenied;
permissionCallbacks.OnPermissionDeniedAndDontAskAgain += OnPermissionDenied;
}
private void Start()
{
Debug.Log("Start");
MLPermissions.RequestPermission(MLPermission.Camera, permissionCallbacks);
MLPermissions.RequestPermission(MLPermission.RecordAudio, permissionCallbacks);
}
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(0.5f);
}
else
{
ConnectCamera();
}
}
Debug.Log("Camera device available");
}
private void Update()
{
// Debug.Log($"Frame Number");
}
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.");
}
}
private void OnPermissionGranted(string permission)
{
MLPluginLog.Debug($"Granted {permission}.");
// TryEnableMLCamera();
}
public void StartVideoCapture()
{
TryEnableMLCamera();
var result = MLPermissions.CheckPermission(MLPermission.Camera);
MLResult.DidNativeCallSucceed(result.Result, nameof(MLPermissions.RequestPermission));
Debug.Log($"CLPermissions.CheckPermission {result}");
if (!result.IsOk)
{
Debug.LogError($"{MLPermission.Camera} permission denied. Video will not be recorded.");
return;
}
StartRecording();
}
private void StartRecording()
{
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._30FPS);
cameraRecorder.StartRecording(recordedFilePath, config);
// Subscribe to the OnInfo event
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();
// Debug.Log($"Video recording started successfully. at {Time.time}");
SharedInfomanager.Instance.SetStartrecordingtime(Time.time);
isCapturingVideo = MLResult.DidNativeCallSucceed(result.Result, nameof(captureCamera.CaptureVideoStart));
if (isCapturingVideo)
{
Debug.Log($"Video recording started successfully. at {Time.time}");
}
}
}
}
public void StopRecording()
{
if (!isCapturingVideo)
{
Debug.LogWarning("No recording is in progress to stop.");
return;
}
captureCamera.CaptureVideoStop();
MLResult result = cameraRecorder.EndRecording();
if (!result.IsOk)
{
Debug.LogError($"Failed to stop recording: {result}");
recordedFilePath = string.Empty;
}
else
{
Debug.Log($"Recording saved at path: {recordedFilePath}");
}
isCapturingVideo = false;
// Disconnect and disable the camera
DisconnectCamera();
}
private void ConnectCamera()
{
MLCamera.ConnectContext context = MLCamera.ConnectContext.Create();
context.Flags = MLCamera.ConnectFlag.MR;
context.EnableVideoStabilization = true;
if (context.Flags != MLCamera.ConnectFlag.CamOnly)
{
context.MixedRealityConnectInfo = MLCamera.MRConnectInfo.Create();
context.MixedRealityConnectInfo.MRQuality = MLCamera.MRQuality._648x720;
context.MixedRealityConnectInfo.MRBlendType = MLCamera.MRBlendType.Additive;
context.MixedRealityConnectInfo.FrameRate = MLCamera.CaptureFrameRate._30FPS;
}
captureCamera = MLCamera.CreateAndConnect(context);
if (captureCamera != null)
{
Debug.Log("Camera device connected");
if (GetImageStreamCapabilities())
{
Debug.Log("Camera stream capabilities received.");
}
}
}
private void DisconnectCamera()
{
if (captureCamera != null)
{
captureCamera.Disconnect();
// MLCamera.Uninitialize();
captureCamera = null;
Debug.Log("Camera disconnected");
}
}
private bool GetImageStreamCapabilities()
{
var result =
captureCamera.GetStreamCapabilities(out MLCamera.StreamCapabilitiesInfo[] streamCapabilitiesInfo);
if (!result.IsOk)
{
Debug.LogError("Failed to get stream capabilities info.");
return false;
}
streamCapabilities = new List<MLCamera.StreamCapability>();
foreach (var info in streamCapabilitiesInfo)
{
streamCapabilities.AddRange(info.StreamCapabilities);
}
return streamCapabilities.Count > 0;
}
}
}