1

我在 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 错误,但每当我单击“拍照”按钮时,就会显示预览窗口它分配内存。如果我按下“Retake”,内存正在被释放,但在 FinishedPiCkingMedia 事件处理程序中我无法释放它。所以,在几张照片之后它崩溃了。

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

再一次感谢你。

4

1 回答 1

1

这是 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 版本,您应该删除解决方法,因为否则您会泄漏缓冲区。

于 2012-02-01T09:20:24.463 回答