2012-01-29 6 views
1

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のバグを排除しますが、「写真を撮る」ボタンをクリックするたびにメモリを割り当てるプレビューウィンドウが表示されます。 「Retake」を押すとメモリが解放されますが、FinishedPiCkingMediaイベントハンドラでは解放できません。だから、いくつかの写真の後でクラッシュします。

解決方法はありますが、私が間違っていることを確認することは素晴らしいことです。

ありがとうございました。

+1

完全なサンプルコード –

+0

をバグレポートhttp://bugzilla.xamarin.comに添付して、この質問に戻ってください。ありがとう! – poupou

答えて

1

これは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バージョンをインストールしたら、回避策を削除する必要があります。そうでなければバッファリングする。

関連する問題