AVCaptureVideoDataOutputSampleBufferDelegate stops after 1 - 3 seconds

Hi
I am trying to capture an MJPEG stream (this is a requirement) using AVCaptureVideoDataOutputSampleBufferDelegate.
After few seconds the AVCaptureVideoDataOutputSampleBufferDelegate.DidOutputSampleBuffer overrider is not called any more.
The video preview on the UI is working OK.
I am building with Xamarin.Forms version 2.5.0.121934, Xcode 9.2 (I have also tried with Xcode 9.1) and I have tested on both iOS 11.1.2 and 11.2

Note I have already implemented (and working) capturing the pictures with AVCaptureStillImageOutput but I am moving to capturing Video since on iOS 11.2 a shutter sound is played on every captured image generating many tik sounds.

I setup the video capture by using the following code:

    AVCaptureSession captureSession = new AVCaptureSession
        {
            SessionPreset = AVCaptureSession.PresetMedium
        };

        AVCaptureVideoPreviewLayer previewLayer = new AVCaptureVideoPreviewLayer(captureSession)
        {
            VideoGravity = AVLayerVideoGravity.ResizeAspectFill,
            Frame = Bounds
        };

        AVCaptureDevice captureDevice = null;
        AVCaptureDevice[] devices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
        if (devices != null)
        {
    //  Find the preferred capture device
        }

        if (captureDevice == null)
        {
            return false;
        }

        AVCaptureDeviceInput captureInput = AVCaptureDeviceInput.FromDevice(captureDevice);
        if (captureInput == null)
        {
            return false;
        }

            CVPixelBufferAttributes settings = new CVPixelBufferAttributes
            {
                PixelFormatType = CVPixelFormatType.CV32BGRA
            };

            AVCaptureVideoDataOutput outputVideo = new AVCaptureVideoDataOutput { WeakVideoSettings = settings.Dictionary };
            outputVideo.AlwaysDiscardsLateVideoFrames = true;

            DispatchQueue queue = new DispatchQueue("myQueue");
            OutputRecorder outputRecorder = new OutputRecorder(this);

            outputVideo.SetSampleBufferDelegateQueue(outputRecorder, queue);


        captureSession.AddInput(captureInput);
        captureSession.AddOutput(outputVideo);

        Layer.AddSublayer(previewLayer);

captureSession.StartRunning();


        captureSession.StartRunning();

The AVCaptureVideoDataOutputSampleBufferDelegate.DidOutputSampleBuffer overrider is also quite simple

        public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
        {
            try
            {
                UIImage image = ImageFromSampleBuffer(sampleBuffer);

                NSData jpegData = image.AsJPEG();
                byte[] bytes = jpegData.ToArray();

                lock (m_Owner.m_syncState)
                {
                    m_Owner.m_LastCapturedFrame = bytes;
                }

                jpegData.Dispose();
            }
            catch (Exception ex)
            {
                DammLogger.Log(DammLoggerLevel.Warn,TAG, ex, "Error getting the video image");
            }
            finally
            {
                sampleBuffer.Dispose();
            }
        }

Have somebody any hint about what I am doing wrong ?

Answers

  • MatteoMonizzaMatteoMonizza ITBeta ✭✭

    I have the same problem.. Did you solved this?

  • BrianLKBrianLK Member ✭✭

    @MatteoMonizza @DomenicodEsposito I am running with the same issue. Did you come to any solution?

  • AkatsukleAkatsukle Member
    edited October 11

    For whatever reason, SetSampleBufferDelegateQueue only keeps a weak reference on your output recorder.
    Hence, your issue is here:

    OutputRecorder outputRecorder = new OutputRecorder(this);
    
    outputVideo.SetSampleBufferDelegateQueue(outputRecorder, queue);
    

    You are creating your OutputRecorder in a local context which means it can get GarbageCollected as soon as the execution leaves your scope.
    Storing the OutputRecorder in a member variable will solve your issue.

    Note that if you are going to give this to your OutputRecorder anyway you may aswell implement IAVCaptureVideoDataOutputSampleBufferDelegate directly, like this:

    [Export("captureOutput:didOutputSampleBuffer:fromConnection:")]
    public void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
    {
        sampleBuffer.Dispose();
    }
    
    [Export("captureOutput:didDropSampleBuffer:fromConnection:")]
    public void DidDropSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
    {
        sampleBuffer.Dispose();
    }
    
Sign In or Register to comment.