私はMonoTouchでリアルタイムのビデオ画像処理を行おうとしています。AVCaptureSessionを使用して、AVCaptureVideoPreviewLayerで動作するカメラからフレームを取得しています。
また、デリゲートクラスでコールバックメソッド「DidOutputSampleBuffer」を正常に取得しました。ただし、結果のCMSampleBufferからUIImageを作成しようとしたすべての方法が失敗します。
キャプチャセッションを設定するコードは次のとおりです。
captureSession = new AVCaptureSession ();
captureSession.BeginConfiguration ();
videoCamera = AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video);
if (videoCamera != null)
{
captureSession.SessionPreset = AVCaptureSession.Preset1280x720;
videoInput = AVCaptureDeviceInput.FromDevice (videoCamera);
if (videoInput != null)
captureSession.AddInput (videoInput);
//DispatchQueue queue = new DispatchQueue ("videoFrameQueue");
videoCapDelegate = new videoOutputDelegate (this);
DispatchQueue queue = new DispatchQueue("videoFrameQueue");
videoOutput = new AVCaptureVideoDataOutput ();
videoOutput.SetSampleBufferDelegateAndQueue (videoCapDelegate, queue);
videoOutput.AlwaysDiscardsLateVideoFrames = true;
videoOutput.VideoSettings.PixelFormat = CVPixelFormatType.CV24RGB;
captureSession.AddOutput (videoOutput);
videoOutput.ConnectionFromMediaType(AVMediaType.Video).VideoOrientation = AVCaptureVideoOrientation.Portrait;
previewLayer = AVCaptureVideoPreviewLayer.FromSession (captureSession);
previewLayer.Frame = UIScreen.MainScreen.Bounds;
previewLayer.AffineTransform = CGAffineTransform.MakeRotation (Convert.DegToRad (-90));
//this.View.Layer.AddSublayer (previewLayer);
captureSession.CommitConfiguration ();
captureSession.StartRunning ();
}
次のように、サンプルバッファの画像バッファからキャストされたCVPixelBufferからCGBitmapContextを作成してみました。
public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, MonoTouch.CoreMedia.CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
{
CVPixelBuffer pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer;
CVReturn flag = pixelBuffer.Lock (0);
if(flag == CVReturn.Success)
{
CGBitmapContext context = new CGBitmapContext
(
pixelBuffer.BaseAddress,
pixelBuffer.Width,
pixelBuffer.Height,
8,
pixelBuffer.BytesPerRow,
CGColorSpace.CreateDeviceRGB (),
CGImageAlphaInfo.PremultipliedFirst
);
UIImage image = new UIImage(context.ToImage());
ProcessImage (image);
pixelBuffer.Unlock(0);
}else
Debug.Print(flag.ToString()
sampleBuffer.Dispose();
}
これにより、次のエラーが発生します
<Error>: CGBitmapContextCreate: invalid data bytes/row: should be at least 2880 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedFirst.
パラメータを微調整しても、ネイティブObjective-cで無効なHandle例外またはsegfaultが発生します。
また、CVImageBufferを使用してCIImageを作成し、そこからUIImageを次のように作成してみました。
public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, MonoTouch.CoreMedia.CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
{
CIImage cImage = new CIImage(sampleBuffer.GetImageBuffer ());
UIImage image = new UIImage(cImage);
ProcessImage (image);
sampleBuffer.Dispose();
}
これにより、CIImageの初期化時に例外が発生します。
NSInvalidArgumentException Reason: -[CIImage initWithCVImageBuffer:]: unrecognized selector sent to instance 0xc821d0
これは正直なところ、MonoTouchのある種のバグのように感じますが、何かが足りない場合や、奇妙な方法でこれを実行しようとしている場合は、別の解決策を教えてください。
ありがとう