videoWriter.release() on iOS causes the app to crash
I’m facing an issue with OpenCV for Unity v2.6.5 where calling videoWriter.release() on iOS causes the app to crash with this error:
-[NSAutoreleasePool retain]: Cannot retain an autorelease pool
I’ve tried moving .release() to OnDisable(), adding a delay, and ensuring videoWriter is properly initialized — but no luck so far. Interestingly, the same setup worked perfectly fine in OpenCV v2.5.9.
I’m currently using Unity 2022.3.59f1. Any ideas on what could be causing this or how to fix it?
`using System.Collections; using System.Collections.Generic; using System.IO; using OpenCVForUnity.CoreModule; using OpenCVForUnity.ImgprocModule; using OpenCVForUnity.UnityUtils.Helper; using OpenCVForUnity.VideoioModule; using UnityEngine;
namespace Utilities { [RequireComponent(typeof(WebCamTexture2MatHelper))] public class OpenCVCameraRecorder : MonoBehaviourInstance<OpenCVCameraRecorder> { #region PrivateVariables
/// <summary>
/// The webcam texture to mat helper.
/// </summary>
private WebCamTexture2MatHelper webCamTextureToMatHelper;
/// <summary>
/// The bgr mat.
/// </summary>
private Mat bgrMat;
private VideoWriter videoWriter;
private bool isRecording = false;
// Path to save recording
private string fileSavePath = null;
#endregion /PrivateVariables
#region UnityMethods
private void OnEnable()
{
GameConstants.IsFaceRecordingConsentGiven = true;
}
private void Start()
{
if (!GameConstants.IsFaceRecordingConsentGiven)
{
return;
}
webCamTextureToMatHelper = gameObject.GetComponent<WebCamTexture2MatHelper>();
webCamTextureToMatHelper.Initialize();
webCamTextureToMatHelper.onInitialized.AddListener(OnWebCamTextureToMatHelperInitialized);
webCamTextureToMatHelper.onDisposed.AddListener(OnWebCamTextureToMatHelperDisposed);
webCamTextureToMatHelper.onErrorOccurred.AddListener(OnWebCamTextureToMatHelperErrorOccurred);
}
private void OnDisable()
{
if (!GameConstants.IsFaceRecordingConsentGiven)
{
return;
}
if (webCamTextureToMatHelper != null)
{
webCamTextureToMatHelper.Dispose();
}
if (isRecording)
{
isRecording = false;
videoWriter?.Dispose();
videoWriter = null;
}
}
private void Update()
{
if (!GameConstants.IsFaceRecordingConsentGiven)
{
return;
}
if (isRecording && webCamTextureToMatHelper.IsPlaying() && webCamTextureToMatHelper.DidUpdateThisFrame())
{
Mat matFrame = webCamTextureToMatHelper.GetMat();
Imgproc.cvtColor(matFrame, bgrMat, Imgproc.COLOR_RGBA2BGR);
videoWriter.write(bgrMat);
}
}
#endregion /UnityMethods
#region WebCamTexture2MatHelperCallback
public void OnWebCamTextureToMatHelperInitialized()
{
Mat webCamTextureMat = webCamTextureToMatHelper.GetMat();
bgrMat = new Mat(webCamTextureMat.rows(), webCamTextureMat.cols(), CvType.CV_8UC3);
Debug.Log("WebCamTextureToMatHelperInitialized");
}
public void OnWebCamTextureToMatHelperDisposed()
{
bgrMat?.Dispose();
}
public void OnWebCamTextureToMatHelperErrorOccurred(Source2MatHelperErrorCode errorCode, string message)
{
Debug.LogError($"WebCamTextureToMatHelperErrorOccurred: {errorCode}, {message}");
}
#endregion /WebCamTexture2MatHelperCallback
#region PublicMethods
public void StartRecording(string filePath)
{
if (!GameConstants.IsFaceRecordingConsentGiven)
{
return;
}
if (isRecording)
{
Debug.LogWarning("Recording is already in progress.");
return;
}
if (bgrMat == null || bgrMat.empty())
{
Debug.LogError("Frame size is invalid. Ensure bgrMat is properly initialized before starting recording.");
return;
}
fileSavePath = filePath;
if (File.Exists(fileSavePath))
{
Debug.LogWarning($"File already exists at path: {fileSavePath}. Deleting existing file.");
File.Delete(fileSavePath);
}
// Get frame properties
int frameWidth = bgrMat.width();
int frameHeight = bgrMat.height();
double fps = webCamTextureToMatHelper.GetFPS();
// Create new VideoWriter each time
videoWriter = new VideoWriter();
int fourcc = VideoWriter.fourcc('H', '2', '6', '4');
videoWriter.open(fileSavePath, fourcc, fps, new Size(frameWidth, frameHeight));
if (!videoWriter.isOpened())
{
Debug.LogError("Failed to open VideoWriter.");
videoWriter.release();
return;
}
isRecording = true;
}
public void StopRecording()
{
if (!GameConstants.IsFaceRecordingConsentGiven)
{
return;
}
if (!isRecording)
{
Debug.LogWarning("Recording is not in progress.");
return;
}
isRecording = false;
// Release synchronously
if (videoWriter != null && !videoWriter.IsDisposed)
{
try
{
videoWriter.release();
}
catch (System.Exception ex)
{
Debug.LogError("Error releasing VideoWriter: " + ex.Message);
}
}
}
#endregion /PublicMethods
}
} `
Thank you very much for reporting.
Do the VideoWriterExample and VideoWriterAsyncExample included in the Examples folder of OpenCVForUnity work fine in your current environment?
Your code specifies fourcc as VideoWriter.fourcc(‘H’, ‘2’, ‘6’, ‘4’), but try changing it to VideoWriter.fourcc(‘M’, ‘J’, ‘P’, ‘G’), the same as the Example code.
Thank you for response, I've try changing it to VideoWriter.fourcc(‘M’, ‘J’, ‘P’, ‘G’), but this crash at the same point.
I tried VideoWriter.fourcc(‘M’, ‘J’, ‘P’, ‘G’) with avi it does created the video output but in corrupted format. however app is not crashed in this scenario.
The following problems are currently reported with opencv. https://github.com/opencv/opencv/issues/19999 Due to this issue, VideoWriter on iOS platform does not seem to work well with fourcc(‘H’, ‘2’, ‘6’,. ‘4’).
can I use any other combination of fourcc and file extension on iOS?
is any update for this issue @EnoxSoftware