Captura de video en iOS con MonoTouch

Tengo el código para crear, configurar e iniciar una session de captura de video en Objective-C que se ejecuta sin problemas. Estoy portando la muestra a C # y MonoTouch 4.0.3 y tengo algunos problemas, aquí está el código:

void Initialize () { // Create notifier delegate class captureVideoDelegate = new CaptureVideoDelegate(this); // Create capture session captureSession = new AVCaptureSession(); captureSession.SessionPreset = AVCaptureSession.Preset640x480; // Create capture device captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video); // Create capture device input NSError error; captureDeviceInput = new AVCaptureDeviceInput(captureDevice, out error); captureSession.AddInput(captureDeviceInput); // Create capture device output captureVideoOutput = new AVCaptureVideoDataOutput(); captureSession.AddOutput(captureVideoOutput); captureVideoOutput.VideoSettings.PixelFormat = CVPixelFormatType.CV32BGRA; captureVideoOutput.MinFrameDuration = new CMTime(1, 30); // // ISSUE 1 // In the original Objective-C code I was creating a dispatch_queue_t object, passing it to // setSampleBufferDelegate:queue message and worked, here I could not find an equivalent to // the queue mechanism. Also not sure if the delegate should be used like this). // captureVideoOutput.SetSampleBufferDelegatequeue(captureVideoDelegate, ???????); // Create preview layer previewLayer = AVCaptureVideoPreviewLayer.FromSession(captureSession); previewLayer.Orientation = AVCaptureVideoOrientation.LandscapeRight; // // ISSUE 2: // Didn't find any VideoGravity related enumeration in MonoTouch (not sure if string will work) // previewLayer.VideoGravity = "AVLayerVideoGravityResizeAspectFill"; previewLayer.Frame = new RectangleF(0, 0, 1024, 768); this.View.Layer.AddSublayer(previewLayer); // Start capture session captureSession.StartRunning(); } #endregion public class CaptureVideoDelegate : AVCaptureVideoDataOutputSampleBufferDelegate { private VirtualDeckViewController mainViewController; public CaptureVideoDelegate(VirtualDeckViewController viewController) { mainViewController = viewController; } public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection) { // TODO: Implement - see: http://go-mono.com/docs/index.aspx?link=T%3aMonoTouch.Foundation.ModelAttribute } } 

Problema 1: No estoy seguro de cómo usar correctamente el delegado en el método SetSampleBufferDelegatequeue. Tampoco se encontró un mecanismo equivalente al object dispatch_queue_t que funciona bien en Objective-C para pasar al segundo parámetro.

Problema 2: No encontré enumeraciones de VideoGravity en las bibliotecas MonoTouch, no estoy seguro de si pasar una cadena con el valor constante funcionará.

He buscado alguna pista para resolver esto, pero no hay muestras claras alnetworkingedor. Cualquier muestra o información sobre cómo hacer lo mismo en MonoTouch sería muy apreciada.

Muchas gracias.

este es el código mío Úsalo bien. Simplemente recorté las cosas importantes, toda la initialization está ahí, así como también la lectura del buffer de salida de muestra.

Luego, código que procesa el formulario CVImageBuffer a una biblioteca ObjC personalizada vinculada, si necesita procesar esto en Monotouch, entonces necesita ir más allá y convertirlo a CGImage o UIImage. No hay ninguna function para eso en Monotouch (AFAIK), por lo que necesita unirlo usted mismo, desde el simple ObjC. La muestra en ObjC está aquí: cómo convertir un CVImageBufferRef a UIImage

 public void InitCapture () { try { // Setup the input NSError error = new NSError (); captureInput = new AVCaptureDeviceInput (AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video), out error); // Setup the output captureOutput = new AVCaptureVideoDataOutput (); captureOutput.AlwaysDiscardsLateVideoFrames = true; captureOutput.SetSampleBufferDelegateAndQueue (avBufferDelegate, dispatchQueue); captureOutput.MinFrameDuration = new CMTime (1, 10); // Set the video output to store frame in BGRA (compatible across devices) captureOutput.VideoSettings = new AVVideoSettings (CVPixelFormatType.CV32BGRA); // Create a capture session captureSession = new AVCaptureSession (); captureSession.SessionPreset = AVCaptureSession.PresetMedium; captureSession.AddInput (captureInput); captureSession.AddOutput (captureOutput); // Setup the preview layer prevLayer = new AVCaptureVideoPreviewLayer (captureSession); prevLayer.Frame = liveView.Bounds; prevLayer.VideoGravity = "AVLayerVideoGravityResize"; // image may be slightly distorted, but networking bar position will be accurate liveView.Layer.AddSublayer (prevLayer); StartLiveDecoding (); } catch (Exception ex) { Console.WriteLine (ex.ToString ()); } } public void DidOutputSampleBuffer (AVCaptureOutput captureOutput, MonoTouch.CoreMedia.CMSampleBuffer sampleBuffer, AVCaptureConnection connection) { Console.WriteLine ("DidOutputSampleBuffer: enter"); if (isScanning) { CVImageBuffer imageBuffer = sampleBuffer.GetImageBuffer (); Console.WriteLine ("DidOutputSampleBuffer: calling decode"); // NSLog(@"got image w=%dh=%d bpr=%d",CVPixelBufferGetWidth(imageBuffer), CVPixelBufferGetHeight(imageBuffer), CVPixelBufferGetBytesPerRow(imageBuffer)); // call the decoder DecodeImage (imageBuffer); } else { Console.WriteLine ("DidOutputSampleBuffer: not scanning"); } Console.WriteLine ("DidOutputSampleBuffer: quit"); } 

Todos los problemas se resolvieron y finalmente funcionaron bien, la congelación estaba sucediendo porque en mi testing no estaba todavía eliminando el sampleBuffer en el método DidOutputSampleBuffer. El código final para mi vista está aquí:

ACTUALIZACIÓN 1 : Se cambió la asignación de VideoSettings CVPixelFormat, fue incorrecta y causaría un BytesPerPixel incorrecto en el sampleBuffer.

 public partial class VirtualDeckViewController : UIViewController { public CaptureVideoDelegate captureVideoDelegate; public AVCaptureVideoPreviewLayer previewLayer; public AVCaptureSession captureSession; public AVCaptureDevice captureDevice; public AVCaptureDeviceInput captureDeviceInput; public AVCaptureVideoDataOutput captureVideoOutput; 

  public override void ViewDidLoad () { base.ViewDidLoad (); SetupVideoCaptureSession(); } public void SetupVideoCaptureSession() { // Create notifier delegate class captureVideoDelegate = new CaptureVideoDelegate(); // Create capture session captureSession = new AVCaptureSession(); captureSession.BeginConfiguration(); captureSession.SessionPreset = AVCaptureSession.Preset640x480; // Create capture device captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video); // Create capture device input NSError error; captureDeviceInput = new AVCaptureDeviceInput(captureDevice, out error); captureSession.AddInput(captureDeviceInput); // Create capture device output captureVideoOutput = new AVCaptureVideoDataOutput(); captureVideoOutput.AlwaysDiscardsLateVideoFrames = true; // UPDATE: Wrong videosettings assignment //captureVideoOutput.VideoSettings.PixelFormat = CVPixelFormatType.CV32BGRA; // UPDATE Correct videosettings assignment captureVideoOutput.VideoSettings = new AVVideoSettings(CVPixelFormatType.CV32BGRA); captureVideoOutput.MinFrameDuration = new CMTime(1, 30); DispatchQueue dispatchQueue = new DispatchQueue("VideoCaptureQueue"); captureVideoOutput.SetSampleBufferDelegateAndQueue(captureVideoDelegate, dispatchQueue); captureSession.AddOutput(captureVideoOutput); // Create preview layer previewLayer = AVCaptureVideoPreviewLayer.FromSession(captureSession); previewLayer.Orientation = AVCaptureVideoOrientation.LandscapeLeft; previewLayer.VideoGravity = "AVLayerVideoGravityResizeAspectFill"; previewLayer.Frame = new RectangleF(0, 0, 1024, 768); this.View.Layer.AddSublayer(previewLayer); // Start capture session captureSession.CommitConfiguration(); captureSession.StartRunning(); } public class CaptureVideoDelegate : AVCaptureVideoDataOutputSampleBufferDelegate { public CaptureVideoDelegate() : base() { } public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection) { // TODO: Implement buffer processing // Very important (buffer needs to be disposed or it will freeze) sampleBuffer.Dispose(); } } 

La pieza final del rompecabezas fue respondida con la muestra de Miguel de Icaza que finalmente encontré aquí: link

Gracias a Miguel y Pavel