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のバグを排除しますが、[写真を撮る]ボタンをクリックするとプレビューウィンドウが表示されますこれはメモリを割り当てます。「再取得」を押すと、メモリが解放されますが、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 に答える