AVCaptureSession CMSampleBuffer问题

问题描述:

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

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的bug,但每当我点击“Take a photo”按钮,预览窗口就会显示分配内存的内容。如果我按“重拍”,内存正在释放,但在FinishedPiCkingMedia事件处理程序中,我无法释放它。所以,在几张照片崩溃之后。

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

再次感谢您。

+1

请发布完整的示例代码 – 2012-01-29 15:40:49

+0

将其附加到http://bugzilla.xamarin.com上的错误报告,并给我们一个链接回到这个问题。谢谢! – poupou 2012-01-29 16:55:01

这是MonoTouch的bug

有一种变通方法,您可以使用,直到你得到修复:

[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(); 
    } 
} 

我添加了一个呼叫处置,有可能是可用缓冲区的数量有限,而且这种方式可以确保应用程序不会耗尽它们(因为在GC自动释放它之前可能需要一些时间)

另请注意,一旦您安装了带有真正修复程序的MonoTouch版本,您应该删除该变通方法,因为您将泄漏否则缓冲。