Skip to content

videoWriter.release() on iOS causes the app to crash #207

@Akash-PlayPowerLabs

Description

@Akash-PlayPowerLabs

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
{
#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
}

}
`

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions