AVCaptureSession CMSampleBuffer 问题

发布于 2024-12-29 08:05:20 字数 4631 浏览 4 评论 0原文

我在从 AVCaptureSession 相机中的 CMSampleBuffer 释放内存时遇到问题。 这是我用于设置捕获会话的代码。如果我处置 imageDataSampleBuffer,应用程序就会崩溃。

using MonoTouch.CoreVideo;
using MonoTouch.CoreMedia;
using MonoTouch.AVFoundation;
using MonoTouch.ImageIO;
using MonoTouch.UIKit;
using MonoTouch.CoreFoundation;
using MonoTouch.Foundation;
using System.Drawing;
using System;
namespace myNamespace
{
public class AVFoundationCamera : UIViewController  
{
    public AVFoundationCamera (CameraController parView)
    {
        parentView = parView;
    }

    NSError error;
    AVCaptureSession session;
    AVCaptureDevice device;
    AVCaptureDeviceInput input;
    AVCaptureStillImageOutput output;
    AVCaptureVideoPreviewLayer captureVideoPreviewLayer;
    NSDictionary outputSettings;


    AVCaptureConnection captureConnection;

    UIButton buttCaptureImage;

    public UIImageView imageV;
    NSData imageData;

    CameraController parentView;

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
        CreateControls();
        SetupSession();

    }

    public override void DidReceiveMemoryWarning ()
    {
        imageData.Dispose();
        session.Dispose();
        device.Dispose();
        input.Dispose();
        output.Dispose();
        captureVideoPreviewLayer.Dispose();
        base.DidReceiveMemoryWarning ();
    }

    private void CreateControls()
    {
        imageV = new UIImageView(new RectangleF(0, 0, UIScreen.MainScreen.ApplicationFrame.Width, UIScreen.MainScreen.ApplicationFrame.Height - UIApplication.SharedApplication.StatusBarFrame.Height));
        View.AddSubview(imageV);

        buttCaptureImage = UIButton.FromType(UIButtonType.RoundedRect);
        buttCaptureImage.Frame = new RectangleF(0, 60, 150, 30);
        buttCaptureImage.SetTitle("Take a photo", UIControlState.Normal);
        buttCaptureImage.TouchUpInside += HandleButtCaptureImageTouchUpInside;

        View.AddSubview(buttCaptureImage);
    }

    void HandleButtCaptureImageTouchUpInside (object sender, EventArgs e)
    {
        captureConnection = null;

        foreach (AVCaptureConnection capConn in output.Connections)
        {
            foreach (AVCaptureInputPort port in capConn.inputPorts)
            {
                if (port.MediaType == AVMediaType.Video)
                {
                    captureConnection = capConn;
                    break;
                }
            }
            if (captureConnection != null)
                break;
        }

        output.CaptureStillImageAsynchronously(captureConnection, HandleAVCaptureCompletionHandlercompletionHandler);
        buttCaptureImage.Enabled = false;
    }

    void HandleAVCaptureCompletionHandlercompletionHandler (CMSampleBuffer imageDataSampleBuffer, NSError error)
    {
        try
        {
            using (var pool = new NSAutoreleasePool ()) {
                imageData = AVCaptureStillImageOutput.JpegStillToNSData(imageDataSampleBuffer);
                //imageDataSampleBuffer.Dispose();
                parentView.DismissModalViewControllerAnimated(true);
                parentView.HandlePickedImage(imageData);
                session.StopRunning();
            }
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }  

    private void SetupSession()
    {

        session = new AVCaptureSession();
        session.BeginConfiguration();
        session.SessionPreset = AVCaptureSession.PresetPhoto;

        captureVideoPreviewLayer = new AVCaptureVideoPreviewLayer(session);
        captureVideoPreviewLayer.Frame = imageV.Bounds;

        imageV.Layer.AddSublayer(captureVideoPreviewLayer);

        device = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);

        input = new AVCaptureDeviceInput(device, out error);

        session.AddInput(input);

        output = new AVCaptureStillImageOutput();
        output.OutputSettings = NSDictionary.FromObjectAndKey(new NSString("AVVideoCodecKey"), new NSString("AVVideoCodecJPEG"));

        session.AddOutput(output);

        session.CommitConfiguration();
        session.StartRunning();
    }
}

只是一个用于拍照的普通相机。我尝试使用您在此处发布的 UIImagePickerController: https://github.com /migueldeicaza/TweetStation/blob/master/TweetStation/UI/Camera.cs 消除了 UIImagePickerController 错误,但每当我单击“拍照”按钮,会出现预览窗口,分配内存。如果我按“重新拍摄”,内存将被释放,但在 FinishedPiCkingMedia 事件处理程序中我无法释放它。所以,拍了几张照片后它就崩溃了。

任何解决方案都适合我,但很高兴看到我做错了什么。

再次感谢您。

I have a problem with releasing memory from CMSampleBuffer in my AVCaptureSession camera.
This is my code for setting capture session. If I dispose imageDataSampleBuffer, app crashes.

using MonoTouch.CoreVideo;
using MonoTouch.CoreMedia;
using MonoTouch.AVFoundation;
using MonoTouch.ImageIO;
using MonoTouch.UIKit;
using MonoTouch.CoreFoundation;
using MonoTouch.Foundation;
using System.Drawing;
using System;
namespace myNamespace
{
public class AVFoundationCamera : UIViewController  
{
    public AVFoundationCamera (CameraController parView)
    {
        parentView = parView;
    }

    NSError error;
    AVCaptureSession session;
    AVCaptureDevice device;
    AVCaptureDeviceInput input;
    AVCaptureStillImageOutput output;
    AVCaptureVideoPreviewLayer captureVideoPreviewLayer;
    NSDictionary outputSettings;


    AVCaptureConnection captureConnection;

    UIButton buttCaptureImage;

    public UIImageView imageV;
    NSData imageData;

    CameraController parentView;

    public override void ViewDidAppear (bool animated)
    {
        base.ViewDidAppear (animated);
        CreateControls();
        SetupSession();

    }

    public override void DidReceiveMemoryWarning ()
    {
        imageData.Dispose();
        session.Dispose();
        device.Dispose();
        input.Dispose();
        output.Dispose();
        captureVideoPreviewLayer.Dispose();
        base.DidReceiveMemoryWarning ();
    }

    private void CreateControls()
    {
        imageV = new UIImageView(new RectangleF(0, 0, UIScreen.MainScreen.ApplicationFrame.Width, UIScreen.MainScreen.ApplicationFrame.Height - UIApplication.SharedApplication.StatusBarFrame.Height));
        View.AddSubview(imageV);

        buttCaptureImage = UIButton.FromType(UIButtonType.RoundedRect);
        buttCaptureImage.Frame = new RectangleF(0, 60, 150, 30);
        buttCaptureImage.SetTitle("Take a photo", UIControlState.Normal);
        buttCaptureImage.TouchUpInside += HandleButtCaptureImageTouchUpInside;

        View.AddSubview(buttCaptureImage);
    }

    void HandleButtCaptureImageTouchUpInside (object sender, EventArgs e)
    {
        captureConnection = null;

        foreach (AVCaptureConnection capConn in output.Connections)
        {
            foreach (AVCaptureInputPort port in capConn.inputPorts)
            {
                if (port.MediaType == AVMediaType.Video)
                {
                    captureConnection = capConn;
                    break;
                }
            }
            if (captureConnection != null)
                break;
        }

        output.CaptureStillImageAsynchronously(captureConnection, HandleAVCaptureCompletionHandlercompletionHandler);
        buttCaptureImage.Enabled = false;
    }

    void HandleAVCaptureCompletionHandlercompletionHandler (CMSampleBuffer imageDataSampleBuffer, NSError error)
    {
        try
        {
            using (var pool = new NSAutoreleasePool ()) {
                imageData = AVCaptureStillImageOutput.JpegStillToNSData(imageDataSampleBuffer);
                //imageDataSampleBuffer.Dispose();
                parentView.DismissModalViewControllerAnimated(true);
                parentView.HandlePickedImage(imageData);
                session.StopRunning();
            }
        }
        catch (Exception exc)
        {
            Console.WriteLine(exc);
        }
    }  

    private void SetupSession()
    {

        session = new AVCaptureSession();
        session.BeginConfiguration();
        session.SessionPreset = AVCaptureSession.PresetPhoto;

        captureVideoPreviewLayer = new AVCaptureVideoPreviewLayer(session);
        captureVideoPreviewLayer.Frame = imageV.Bounds;

        imageV.Layer.AddSublayer(captureVideoPreviewLayer);

        device = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);

        input = new AVCaptureDeviceInput(device, out error);

        session.AddInput(input);

        output = new AVCaptureStillImageOutput();
        output.OutputSettings = NSDictionary.FromObjectAndKey(new NSString("AVVideoCodecKey"), new NSString("AVVideoCodecJPEG"));

        session.AddOutput(output);

        session.CommitConfiguration();
        session.StartRunning();
    }
}

}

This is just a regular camera for taking photos. I tried with UIImagePickerController you posted here: https://github.com/migueldeicaza/TweetStation/blob/master/TweetStation/UI/Camera.cs which eliminates UIImagePickerController bug but whenever I click "Take a photo" button, preview window shows up which allocates memory. If I press "Retake", memory is being released, but in FinishedPiCkingMedia event handler I can't release it. So, after few photos it crashes.

Any solution works for me, but it would be great to see what I'm doing wrong.

Thank you once again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情场扛把子 2025-01-05 08:05:20

这是 MonoTouch 中的一个错误

在获得修复之前,您可以使用一种解决方法:

[DllImport ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
extern static void CFRetain (IntPtr handle);

void HandleAVCaptureCompletionHandlercompletionHandler (CMSampleBuffer imageDataSampleBuffer, NSError error)
{
    try {
        CFRetain (imageDataSampleBuffer.Handle);
        (...)
    } finally {
        imageDataSampleBuffer.Dispose ();
    }
}

我添加了一个 Dispose 调用,可用的缓冲区数量可能有限,这样您就可以确保应用程序不会耗尽它们(因为它可能需要GC 会自动释放它之前很短的时间)

还要注意,一旦您安装了具有真正修复功能的 MonoTouch 版本,您应该删除该解决方法,因为否则您将泄漏缓冲区。

This was a bug in MonoTouch.

There is a workaround you can use until you get the fix:

[DllImport ("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")]
extern static void CFRetain (IntPtr handle);

void HandleAVCaptureCompletionHandlercompletionHandler (CMSampleBuffer imageDataSampleBuffer, NSError error)
{
    try {
        CFRetain (imageDataSampleBuffer.Handle);
        (...)
    } finally {
        imageDataSampleBuffer.Dispose ();
    }
}

I've added a Dispose call, there might be a limited amount of buffers available, and this way you ensure that the app doesn't exhaust them (since it may take a little time before the GC would free it automatically)

Also note that you should remove the workaround once you install a MonoTouch version with the real fix, since you'll leak the buffers otherwise.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文