Bug 3133 - Releasing of CMSampleBuffer in AVCaptureSession causes crash
Summary: Releasing of CMSampleBuffer in AVCaptureSession causes crash
Status: RESOLVED DUPLICATE of bug 1062
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: 5.0
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-01-29 18:00 UTC by Daniel
Modified: 2012-01-31 09:14 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED DUPLICATE of bug 1062

Description Daniel 2012-01-29 18:00:10 UTC
Overview - After capturing a photo or movie from AVCaptureSession, CMSamplerBuffer cannot be disposed.

Steps to reproduce - Present view controller with AVCaptureSession and take a photo

Results - app crashes

Expected - Memory should be released so camera can be used many times

Link to stackoverflow - http://stackoverflow.com/questions/9050882/avcapturesession-cmsamplebuffer-issue 

Code - 

using System;
using MonoTouch.CoreVideo;
using MonoTouch.CoreMedia;
using MonoTouch.AVFoundation;
using MonoTouch.ImageIO;
using MonoTouch.UIKit;
using MonoTouch.CoreFoundation;
using MonoTouch.Foundation;
using System.Drawing;

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;
		DispatchQueue dispatchQueue;
		
		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();
		}
	}
}
Comment 1 Rolf Bjarne Kvinge [MSFT] 2012-01-30 07:37:49 UTC
Can you provide a complete sample? I get a compiler error about CameraController when trying to compile your project.
Comment 2 Daniel 2012-01-30 15:08:18 UTC
Sorry for posting incomplete code. This sample is consisted of two classes. Just create an instance of CameraController and it will present AVFoundationCamera. Thank you very much.

using System;
using MonoTouch.UIKit;
using System.Drawing;
using System.Collections.Generic;
using MonoTouch.Foundation;
using MonoTouch.AssetsLibrary;
using System.IO;
using System.Threading;

namespace Camera
{
	public class CameraController : UIViewController
	{
		UIScrollView scrollContent;
		UIImage capturedImage;
		UIImage smallImage;
		UIImageView capturedImageV;
		UITextView tfNote;
		UIButton buttSave;
		
		UIImage imgTfBackground;
		UIImage imgTfBackgroundTile;
		UIImageView imgVTfBackground;
		
		NSDictionary dict;
		string photoUrl;
		
		NSData imgData;
		NSError error;
		
		bool disappearToCamera;
		
		bool showCamera = true;
		bool shouldDispose;
		
		UIActivityIndicatorView activityView;
		
		NSObject keyboardShow;
		NSObject keyboardHide;
		
		AVFoundationCamera customCamera;
		
		string path;
		
		public CameraController ()
		{

		}
		
		public override void DidReceiveMemoryWarning ()
		{
			base.DidReceiveMemoryWarning (); Console.WriteLine("error");
			capturedImage.Dispose();
			smallImage.Dispose();
			capturedImageV.Dispose();
			tfNote.Dispose();
			buttSave.Dispose();
			
			imgData.Dispose();
		}
		
		public override void ViewDidLoad ()
		{
			base.ViewDidLoad ();
			Title = "Photo";
			disappearToCamera = true;

			if (UIImagePickerController.IsSourceTypeAvailable(UIImagePickerControllerSourceType.Camera))
			{
				CreateControls();
				AddControls ();
			}
		}
		
		public override void ViewWillAppear (bool animated)
		{
			if (customCamera == null)
			{
				customCamera = new AVFoundationCamera(this);
				PresentModalViewController(customCamera, true);
			}
			base.ViewWillAppear (animated);
			
			capturedImage = new UIImage();
			
			keyboardShow = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, delegate(NSNotification n)
			{
				ShowHideKeyboard("show", n);
			});
			keyboardHide = NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillHideNotification, delegate(NSNotification n)
			{
				ShowHideKeyboard ("hide", n);
			});
		}
		
		public override void ViewWillDisappear (bool animated)
		{
			base.ViewWillDisappear (animated);
			
			if (keyboardShow != null)
			{
				NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardShow);
				NSNotificationCenter.DefaultCenter.RemoveObserver(keyboardHide);
				
				keyboardShow.Dispose();
				keyboardHide.Dispose();
			}
		}
		
		private void ShowHideKeyboard (string s, NSNotification n)
		{
			PointF scrollPoint;

			if (s == "show")
			{
				RectangleF keyboardRect = UIKeyboard.BoundsFromNotification(n);
				double duration = UIKeyboard.AnimationDurationFromNotification(n);
				
				
				RectangleF currentRect = View.Bounds;
				currentRect.Height -= keyboardRect.Height - 60;
				
				UIView.Animate (duration, delegate() {
					scrollContent.Frame = currentRect; 
					scrollContent.SetContentOffset(new PointF(0, 160), true);
				});
				
			}
			else
			{
				double duration = UIKeyboard.AnimationDurationFromNotification(n);
				UIView.Animate(duration, delegate() {
				scrollContent.Frame = new RectangleF(new PointF(0, 0), View.Bounds.Size);	
				});
			}
		}
		
		public void CreateControls()
		{
			scrollContent = new UIScrollView();
			
			capturedImageV = new UIImageView();
			capturedImageV.Frame = new RectangleF(10, 10, UIScreen.MainScreen.ApplicationFrame.Width - 20, 160);
			capturedImageV.ContentMode = UIViewContentMode.ScaleAspectFit;
			capturedImageV.Alpha = 0;
			
			
			                                                           
			
			tfNote = new UITextView();
			tfNote.Frame = new RectangleF(14, capturedImageV.Frame.Y + capturedImageV.Frame.Height + 25, UIScreen.MainScreen.ApplicationFrame.Width - 28, 70);
			tfNote.BackgroundColor = UIColor.DarkGray;
			tfNote.TextAlignment = UITextAlignment.Left;
			tfNote.BackgroundColor = UIColor.Red;
			tfNote.TextColor = UIColor.FromRGB(0, 0, 0);
			tfNote.BackgroundColor = UIColor.Clear;
			tfNote.ScrollsToTop = true;
			tfNote.IndicatorStyle = UIScrollViewIndicatorStyle.Black;
			tfNote.Font = UIFont.FromName("Helvetica", 16);
			buttSave = UIButton.FromType(UIButtonType.RoundedRect);
			buttSave.SetTitle("Press me", UIControlState.Normal);
			buttSave.Frame = new RectangleF(10, tfNote.Frame.Y + tfNote.Frame.Height + 20, UIScreen.MainScreen.ApplicationFrame.Width - 20, 60);
			buttSave.TouchUpInside += HandleButtSaveTouchUpInside;
			
			activityView = new UIActivityIndicatorView(new RectangleF(UIScreen.MainScreen.ApplicationFrame.Width / 2 - 18, UIScreen.MainScreen.ApplicationFrame.Height / 2 - 160, 35, 35));
			activityView.ActivityIndicatorViewStyle = UIActivityIndicatorViewStyle.White;
			
			scrollContent.AddSubview(capturedImageV);
			scrollContent.AddSubview(tfNote);
			scrollContent.AddSubview(buttSave);
			scrollContent.AddSubview(activityView);
		}

		void HandleButtSaveTouchUpInside (object sender, EventArgs e)
		{
			PresentModalViewController(customCamera, true);
//			try
//			{
//				tfNote.ResignFirstResponder();
//				imgData = smallImage.AsJPEG();
//					
//				error = null;
//				CreateImagePath();
//				imgData.Save(path + ".jpg", false, out error);
//
//				capturedImageV.Dispose();
//
//				imgData.Dispose();
//			}
//			catch (Exception exc)
//			{
//				Console.WriteLine(exc);
//			}
		}
		
		public void HandlePickedImage (NSData imagData)
		{
			photoUrl = Guid.NewGuid().ToString();
			disappearToCamera = false;
			
			activityView.StartAnimating();
			capturedImage = new UIImage(imagData);
			if (capturedImage.Orientation == UIImageOrientation.Down || capturedImage.Orientation == UIImageOrientation.Up || capturedImage.Orientation == UIImageOrientation.DownMirrored || capturedImage.Orientation == UIImageOrientation.UpMirrored)
			{
				smallImage = capturedImage.Scale(new SizeF(800, 600));
			}
			else
			{
				smallImage = capturedImage.Scale(new SizeF(600, 800));
			}

			FillSmallImage ();
			
			activityView.StopAnimating();
			activityView.Dispose();
			capturedImage.Dispose();
			capturedImageV.Dispose();
			
		}
		
		private void FillSmallImage()
		{
			if (capturedImage != null)
			{
				capturedImageV.Image = smallImage;
				UIView.Animate(1, delegate() {
					capturedImageV.Alpha = 1;
				});
			}
		}
		
		private void CreateImagePath ()
		{
			path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), photoUrl);
		}

		void HandleImagePickerControllerCanceled (object sender, EventArgs e)
		{
			NavigationController.PopViewControllerAnimated(true);
		}
		
		public void AddControls()
		{
			scrollContent.Frame = new RectangleF(0, 0, UIScreen.MainScreen.ApplicationFrame.Width, UIScreen.MainScreen.ApplicationFrame.Height);
			scrollContent.ContentSize = new SizeF(UIScreen.MainScreen.ApplicationFrame.Width, buttSave.Frame.Y + buttSave.Frame.Height + 20);
			View.AddSubview(scrollContent);
			
		}
		
	}
	
}


------------------------------

Here's the camera controller

------------------------------

using System;
using MonoTouch.CoreVideo;
using MonoTouch.CoreMedia;
using MonoTouch.AVFoundation;
using MonoTouch.ImageIO;
using MonoTouch.UIKit;
using MonoTouch.CoreFoundation;
using MonoTouch.Foundation;
using System.Drawing;

namespace Camera
{
	public class AVFoundationCamera : UIViewController	
	{
		public AVFoundationCamera (CameraController parView)
		{
			
			parentView = parView;
		}
		
		NSError error;
		AVCaptureSession session;
		AVCaptureDevice device;
		AVCaptureDeviceInput input;
		AVCaptureStillImageOutput output;
		AVCaptureVideoPreviewLayer captureVideoPreviewLayer;
		NSDictionary outputSettings;
		DispatchQueue dispatchQueue;
		
		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);
					
					parentView.DismissModalViewControllerAnimated(true);
					parentView.HandlePickedImage(imageData);
					imageDataSampleBuffer.Dispose();
					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();
		}
	}
}
Comment 3 Rolf Bjarne Kvinge [MSFT] 2012-01-31 09:14:22 UTC
This is a dup of #1062.

*** This bug has been marked as a duplicate of bug 1062 ***