[opencv] 01/89: highgui: clone cap_avfoundation_mac.mm from master
Nobuhiro Iwamatsu
iwamatsu at moszumanska.debian.org
Sat May 13 09:57:19 UTC 2017
This is an automated email from the git hooks/post-receive script.
iwamatsu pushed a commit to annotated tag 2.4.13.2
in repository opencv.
commit 3648c6117225bc1e385bfd10b1e63b1e943c9f0d
Author: Alexander Alekhin <alexander.alekhin at intel.com>
Date: Mon Sep 19 19:46:42 2016 +0300
highgui: clone cap_avfoundation_mac.mm from master
---
modules/highgui/src/cap_avfoundation_mac.mm | 1322 +++++++++++++++++++++++++++
1 file changed, 1322 insertions(+)
diff --git a/modules/highgui/src/cap_avfoundation_mac.mm b/modules/highgui/src/cap_avfoundation_mac.mm
new file mode 100644
index 0000000..8c30506
--- /dev/null
+++ b/modules/highgui/src/cap_avfoundation_mac.mm
@@ -0,0 +1,1322 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the contributor be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*////////////////////////////////////////////////////////////////////////////////////////
+
+
+#include "precomp.hpp"
+#include "opencv2/imgproc.hpp"
+#include <stdio.h>
+#import <AVFoundation/AVFoundation.h>
+
+/********************** Declaration of class headers ************************/
+
+/*****************************************************************************
+ *
+ * CaptureDelegate Declaration.
+ *
+ * CaptureDelegate is notified on a separate thread by the OS whenever there
+ * is a new frame. When "updateImage" is called from the main thread, it
+ * copies this new frame into an IplImage, but only if this frame has not
+ * been copied before. When "getOutput" is called from the main thread,
+ * it gives the last copied IplImage.
+ *
+ *****************************************************************************/
+
+
+ at interface CaptureDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
+{
+ NSCondition *mHasNewFrame;
+ CVPixelBufferRef mGrabbedPixels;
+ CVImageBufferRef mCurrentImageBuffer;
+ IplImage *mDeviceImage;
+ uint8_t *mOutImagedata;
+ IplImage *mOutImage;
+ size_t currSize;
+}
+
+- (void)captureOutput:(AVCaptureOutput *)captureOutput
+didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
+ fromConnection:(AVCaptureConnection *)connection;
+
+- (BOOL)grabImageUntilDate: (NSDate *)limit;
+- (int)updateImage;
+- (IplImage*)getOutput;
+
+ at end
+
+/*****************************************************************************
+ *
+ * CvCaptureCAM Declaration.
+ *
+ * CvCaptureCAM is the instantiation of a capture source for cameras.
+ *
+ *****************************************************************************/
+
+class CvCaptureCAM : public CvCapture {
+public:
+ CvCaptureCAM(int cameraNum = -1) ;
+ ~CvCaptureCAM();
+ virtual bool grabFrame();
+ virtual IplImage* retrieveFrame(int);
+ virtual double getProperty(int property_id) const;
+ virtual bool setProperty(int property_id, double value);
+ virtual int didStart();
+
+
+private:
+ AVCaptureSession *mCaptureSession;
+ AVCaptureDeviceInput *mCaptureDeviceInput;
+ AVCaptureVideoDataOutput *mCaptureVideoDataOutput;
+ AVCaptureDevice *mCaptureDevice;
+ CaptureDelegate *mCapture;
+
+ int startCaptureDevice(int cameraNum);
+ void stopCaptureDevice();
+
+ void setWidthHeight();
+ bool grabFrame(double timeOut);
+
+ int camNum;
+ int width;
+ int height;
+ int settingWidth;
+ int settingHeight;
+ OSType mInputPixelFormat;
+
+ int started;
+};
+
+
+/*****************************************************************************
+ *
+ * CvCaptureFile Declaration.
+ *
+ * CvCaptureFile is the instantiation of a capture source for video files.
+ *
+ *****************************************************************************/
+
+class CvCaptureFile : public CvCapture {
+public:
+ CvCaptureFile(const char* filename) ;
+ ~CvCaptureFile();
+ virtual bool grabFrame();
+ virtual IplImage* retrieveFrame(int);
+ virtual double getProperty(int property_id) const;
+ virtual bool setProperty(int property_id, double value);
+ virtual int didStart();
+
+
+private:
+ AVAsset *mAsset;
+ AVAssetTrack *mAssetTrack;
+ AVAssetReader *mAssetReader;
+ AVAssetReaderTrackOutput *mTrackOutput;
+
+ CMSampleBufferRef mCurrentSampleBuffer;
+ CVImageBufferRef mGrabbedPixels;
+ IplImage *mDeviceImage;
+ uint8_t *mOutImagedata;
+ IplImage *mOutImage;
+ size_t currSize;
+ int mMode;
+ int mFormat;
+
+ bool setupReadingAt(CMTime position);
+ IplImage* retrieveFramePixelBuffer();
+
+ CMTime mFrameTimestamp;
+ size_t mFrameNum;
+ OSType mInputPixelFormat;
+
+ int started;
+};
+
+
+/*****************************************************************************
+ *
+ * CvVideoWriter_AVFoundation Declaration.
+ *
+ * CvVideoWriter_AVFoundation is the instantiation of a video output class.
+ *
+ *****************************************************************************/
+
+class CvVideoWriter_AVFoundation : public CvVideoWriter {
+ public:
+ CvVideoWriter_AVFoundation(const char* filename, int fourcc,
+ double fps, CvSize frame_size,
+ int is_color=1);
+ ~CvVideoWriter_AVFoundation();
+ bool writeFrame(const IplImage* image);
+ private:
+ IplImage* argbimage;
+
+ AVAssetWriter *mMovieWriter;
+ AVAssetWriterInput* mMovieWriterInput;
+ AVAssetWriterInputPixelBufferAdaptor* mMovieWriterAdaptor;
+
+ NSString* path;
+ NSString* codec;
+ NSString* fileType;
+ double mMovieFPS;
+ CvSize movieSize;
+ int movieColor;
+ unsigned long mFrameNum;
+};
+
+/****************** Implementation of interface functions ********************/
+
+
+CvCapture* cvCreateFileCapture_AVFoundation(const char* filename) {
+ CvCaptureFile *retval = new CvCaptureFile(filename);
+
+ if(retval->didStart())
+ return retval;
+ delete retval;
+ return NULL;
+}
+
+CvCapture* cvCreateCameraCapture_AVFoundation(int index ) {
+ CvCapture* retval = new CvCaptureCAM(index);
+ if (!((CvCaptureCAM *)retval)->didStart())
+ cvReleaseCapture(&retval);
+ return retval;
+}
+
+CvVideoWriter* cvCreateVideoWriter_AVFoundation(const char* filename, int fourcc,
+ double fps, CvSize frame_size,
+ int is_color) {
+ return new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size,is_color);
+}
+
+/********************** Implementation of Classes ****************************/
+
+/*****************************************************************************
+ *
+ * CvCaptureCAM Implementation.
+ *
+ * CvCaptureCAM is the instantiation of a capture source for cameras.
+ *
+ *****************************************************************************/
+
+CvCaptureCAM::CvCaptureCAM(int cameraNum) {
+ mCaptureSession = nil;
+ mCaptureDeviceInput = nil;
+ mCaptureVideoDataOutput = nil;
+ mCaptureDevice = nil;
+ mCapture = nil;
+
+ width = 0;
+ height = 0;
+ settingWidth = 0;
+ settingHeight = 0;
+
+ camNum = cameraNum;
+
+ if ( ! startCaptureDevice(camNum) ) {
+ fprintf(stderr, "OpenCV: camera failed to properly initialize!\n");
+ started = 0;
+ } else {
+ started = 1;
+ }
+}
+
+CvCaptureCAM::~CvCaptureCAM() {
+ stopCaptureDevice();
+}
+
+int CvCaptureCAM::didStart() {
+ return started;
+}
+
+
+bool CvCaptureCAM::grabFrame() {
+ return grabFrame(1);
+}
+
+bool CvCaptureCAM::grabFrame(double timeOut) {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ bool isGrabbed = false;
+ NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: timeOut];
+ if ( [mCapture grabImageUntilDate: limit] ) {
+ [mCapture updateImage];
+ isGrabbed = true;
+ }
+
+ [localpool drain];
+ return isGrabbed;
+}
+
+IplImage* CvCaptureCAM::retrieveFrame(int) {
+ return [mCapture getOutput];
+}
+
+void CvCaptureCAM::stopCaptureDevice() {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ [mCaptureSession stopRunning];
+
+ [mCaptureSession release];
+ [mCaptureDeviceInput release];
+ [mCaptureDevice release];
+
+ [mCaptureVideoDataOutput release];
+ [mCapture release];
+
+ [localpool drain];
+}
+
+int CvCaptureCAM::startCaptureDevice(int cameraNum) {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ // get capture device
+ NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
+
+ if ( devices.count == 0 ) {
+ fprintf(stderr, "OpenCV: AVFoundation didn't find any attached Video Input Devices!\n");
+ [localpool drain];
+ return 0;
+ }
+
+ if ( cameraNum < 0 || devices.count <= NSUInteger(cameraNum) ) {
+ fprintf(stderr, "OpenCV: out device of bound (0-%ld): %d\n", devices.count-1, cameraNum);
+ [localpool drain];
+ return 0;
+ }
+
+ mCaptureDevice = devices[cameraNum];
+
+ if ( ! mCaptureDevice ) {
+ fprintf(stderr, "OpenCV: device %d not able to use.\n", cameraNum);
+ [localpool drain];
+ return 0;
+ }
+
+ // get input device
+ NSError *error = nil;
+ mCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice: mCaptureDevice
+ error: &error];
+ if ( error ) {
+ fprintf(stderr, "OpenCV: error in [AVCaptureDeviceInput initWithDevice:error:]\n");
+ NSLog(@"OpenCV: %@", error.localizedDescription);
+ [localpool drain];
+ return 0;
+ }
+
+ // create output
+ mCapture = [[CaptureDelegate alloc] init];
+ mCaptureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
+ dispatch_queue_t queue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL);
+ [mCaptureVideoDataOutput setSampleBufferDelegate: mCapture queue: queue];
+ dispatch_release(queue);
+
+ OSType pixelFormat = kCVPixelFormatType_32BGRA;
+ //OSType pixelFormat = kCVPixelFormatType_422YpCbCr8;
+ NSDictionary *pixelBufferOptions;
+ if (width > 0 && height > 0) {
+ pixelBufferOptions =
+ @{
+ (id)kCVPixelBufferWidthKey: @(1.0*width),
+ (id)kCVPixelBufferHeightKey: @(1.0*height),
+ (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+ };
+ } else {
+ pixelBufferOptions =
+ @{
+ (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+ };
+ }
+ mCaptureVideoDataOutput.videoSettings = pixelBufferOptions;
+ mCaptureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;
+
+ // create session
+ mCaptureSession = [[AVCaptureSession alloc] init];
+ mCaptureSession.sessionPreset = AVCaptureSessionPresetMedium;
+ [mCaptureSession addInput: mCaptureDeviceInput];
+ [mCaptureSession addOutput: mCaptureVideoDataOutput];
+
+ [mCaptureSession startRunning];
+
+ // flush old position image
+ grabFrame(1);
+
+ [localpool drain];
+ return 1;
+}
+
+void CvCaptureCAM::setWidthHeight() {
+ NSMutableDictionary *pixelBufferOptions = [mCaptureVideoDataOutput.videoSettings mutableCopy];
+
+ while ( true ) {
+ // auto matching
+ pixelBufferOptions[(id)kCVPixelBufferWidthKey] = @(1.0*width);
+ pixelBufferOptions[(id)kCVPixelBufferHeightKey] = @(1.0*height);
+ mCaptureVideoDataOutput.videoSettings = pixelBufferOptions;
+
+ // compare matched size and my options
+ CMFormatDescriptionRef format = mCaptureDevice.activeFormat.formatDescription;
+ CMVideoDimensions deviceSize = CMVideoFormatDescriptionGetDimensions(format);
+ if ( deviceSize.width == width && deviceSize.height == height ) {
+ break;
+ }
+
+ // fit my options to matched size
+ width = deviceSize.width;
+ height = deviceSize.height;
+ }
+
+ // flush old size image
+ grabFrame(1);
+
+ [pixelBufferOptions release];
+}
+
+
+double CvCaptureCAM::getProperty(int property_id) const{
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ CMFormatDescriptionRef format = mCaptureDevice.activeFormat.formatDescription;
+ CMVideoDimensions s1 = CMVideoFormatDescriptionGetDimensions(format);
+ double retval = 0;
+
+ switch (property_id) {
+ case CV_CAP_PROP_FRAME_WIDTH:
+ retval = s1.width;
+ break;
+ case CV_CAP_PROP_FRAME_HEIGHT:
+ retval = s1.height;
+ break;
+ case CV_CAP_PROP_FPS:
+ {
+ CMTime frameDuration = mCaptureDevice.activeVideoMaxFrameDuration;
+ retval = frameDuration.timescale / double(frameDuration.value);
+ }
+ break;
+ case CV_CAP_PROP_FORMAT:
+ retval = CV_8UC3;
+ break;
+ default:
+ break;
+ }
+
+ [localpool drain];
+ return retval;
+}
+
+bool CvCaptureCAM::setProperty(int property_id, double value) {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ bool isSucceeded = false;
+
+ switch (property_id) {
+ case CV_CAP_PROP_FRAME_WIDTH:
+ width = value;
+ settingWidth = 1;
+ if (settingWidth && settingHeight) {
+ setWidthHeight();
+ settingWidth = 0;
+ settingHeight = 0;
+ }
+ isSucceeded = true;
+ break;
+ case CV_CAP_PROP_FRAME_HEIGHT:
+ height = value;
+ settingHeight = 1;
+ if (settingWidth && settingHeight) {
+ setWidthHeight();
+ settingWidth = 0;
+ settingHeight = 0;
+ }
+ isSucceeded = true;
+ break;
+ case CV_CAP_PROP_FPS:
+ if ( [mCaptureDevice lockForConfiguration: NULL] ) {
+ NSArray * ranges = mCaptureDevice.activeFormat.videoSupportedFrameRateRanges;
+ AVFrameRateRange *matchedRange = ranges[0];
+ double minDiff = fabs(matchedRange.maxFrameRate - value);
+ for ( AVFrameRateRange *range in ranges ) {
+ double diff = fabs(range.maxFrameRate - value);
+ if ( diff < minDiff ) {
+ minDiff = diff;
+ matchedRange = range;
+ }
+ }
+ mCaptureDevice.activeVideoMinFrameDuration = matchedRange.minFrameDuration;
+ mCaptureDevice.activeVideoMaxFrameDuration = matchedRange.minFrameDuration;
+ isSucceeded = true;
+ [mCaptureDevice unlockForConfiguration];
+ }
+ break;
+ default:
+ break;
+ }
+
+ [localpool drain];
+ return isSucceeded;
+}
+
+
+/*****************************************************************************
+ *
+ * CaptureDelegate Implementation.
+ *
+ * CaptureDelegate is notified on a separate thread by the OS whenever there
+ * is a new frame. When "updateImage" is called from the main thread, it
+ * copies this new frame into an IplImage, but only if this frame has not
+ * been copied before. When "getOutput" is called from the main thread,
+ * it gives the last copied IplImage.
+ *
+ *****************************************************************************/
+
+
+ at implementation CaptureDelegate
+
+- (id)init {
+ [super init];
+ mHasNewFrame = [[NSCondition alloc] init];
+ mCurrentImageBuffer = NULL;
+ mGrabbedPixels = NULL;
+ mDeviceImage = NULL;
+ mOutImagedata = NULL;
+ mOutImage = NULL;
+ currSize = 0;
+ return self;
+}
+
+-(void)dealloc {
+ free(mOutImagedata);
+ cvReleaseImage(&mOutImage);
+ cvReleaseImage(&mDeviceImage);
+ CVBufferRelease(mCurrentImageBuffer);
+ CVBufferRelease(mGrabbedPixels);
+ [mHasNewFrame release];
+ [super dealloc];
+}
+
+- (void)captureOutput:(AVCaptureOutput *)captureOutput
+didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
+ fromConnection:(AVCaptureConnection *)connection {
+ (void)captureOutput;
+ (void)sampleBuffer;
+ (void)connection;
+
+ CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
+ CVBufferRetain(imageBuffer);
+
+ [mHasNewFrame lock];
+
+ CVBufferRelease(mCurrentImageBuffer);
+ mCurrentImageBuffer = imageBuffer;
+ [mHasNewFrame signal];
+
+ [mHasNewFrame unlock];
+
+}
+
+-(IplImage*) getOutput {
+ return mOutImage;
+}
+
+-(BOOL) grabImageUntilDate: (NSDate *)limit {
+ BOOL isGrabbed = NO;
+ [mHasNewFrame lock];
+
+ if ( mGrabbedPixels ) {
+ CVBufferRelease(mGrabbedPixels);
+ }
+ if ( [mHasNewFrame waitUntilDate: limit] ) {
+ isGrabbed = YES;
+ mGrabbedPixels = CVBufferRetain(mCurrentImageBuffer);
+ }
+
+ [mHasNewFrame unlock];
+ return isGrabbed;
+}
+
+-(int) updateImage {
+ if ( ! mGrabbedPixels ) {
+ return 0;
+ }
+
+ CVPixelBufferLockBaseAddress(mGrabbedPixels, 0);
+ void *baseaddress = CVPixelBufferGetBaseAddress(mGrabbedPixels);
+
+ size_t width = CVPixelBufferGetWidth(mGrabbedPixels);
+ size_t height = CVPixelBufferGetHeight(mGrabbedPixels);
+ size_t rowBytes = CVPixelBufferGetBytesPerRow(mGrabbedPixels);
+ OSType pixelFormat = CVPixelBufferGetPixelFormatType(mGrabbedPixels);
+
+ if ( rowBytes == 0 ) {
+ fprintf(stderr, "OpenCV: error: rowBytes == 0\n");
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ return 0;
+ }
+
+ if ( currSize != width*3*height ) {
+ currSize = width*3*height;
+ free(mOutImagedata);
+ mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+ }
+
+ if (mOutImage == NULL) {
+ mOutImage = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 3);
+ }
+ mOutImage->width = int(width);
+ mOutImage->height = int(height);
+ mOutImage->nChannels = 3;
+ mOutImage->depth = IPL_DEPTH_8U;
+ mOutImage->widthStep = int(width*3);
+ mOutImage->imageData = reinterpret_cast<char *>(mOutImagedata);
+ mOutImage->imageSize = int(currSize);
+
+ if ( pixelFormat == kCVPixelFormatType_32BGRA ) {
+ if (mDeviceImage == NULL) {
+ mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, 4);
+ }
+ mDeviceImage->width = int(width);
+ mDeviceImage->height = int(height);
+ mDeviceImage->nChannels = 4;
+ mDeviceImage->depth = IPL_DEPTH_8U;
+ mDeviceImage->widthStep = int(rowBytes);
+ mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+ mDeviceImage->imageSize = int(rowBytes*height);
+
+ cvCvtColor(mDeviceImage, mOutImage, CV_BGRA2BGR);
+ } else if ( pixelFormat == kCVPixelFormatType_422YpCbCr8 ) {
+ if ( currSize != width*3*height ) {
+ currSize = width*3*height;
+ free(mOutImagedata);
+ mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+ }
+
+ if (mDeviceImage == NULL) {
+ mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, 2);
+ }
+ mDeviceImage->width = int(width);
+ mDeviceImage->height = int(height);
+ mDeviceImage->nChannels = 2;
+ mDeviceImage->depth = IPL_DEPTH_8U;
+ mDeviceImage->widthStep = int(rowBytes);
+ mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+ mDeviceImage->imageSize = int(rowBytes*height);
+
+ cvCvtColor(mDeviceImage, mOutImage, CV_YUV2BGR_UYVY);
+ } else {
+ fprintf(stderr, "OpenCV: unknown pixel format 0x%08X\n", pixelFormat);
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ return 0;
+ }
+
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+
+ return 1;
+}
+
+ at end
+
+
+/*****************************************************************************
+ *
+ * CvCaptureFile Implementation.
+ *
+ * CvCaptureFile is the instantiation of a capture source for video files.
+ *
+ *****************************************************************************/
+
+CvCaptureFile::CvCaptureFile(const char* filename) {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ mAsset = nil;
+ mAssetTrack = nil;
+ mAssetReader = nil;
+ mTrackOutput = nil;
+ mDeviceImage = NULL;
+ mOutImage = NULL;
+ mOutImagedata = NULL;
+ currSize = 0;
+ mMode = CV_CAP_MODE_BGR;
+ mFormat = CV_8UC3;
+ mCurrentSampleBuffer = NULL;
+ mGrabbedPixels = NULL;
+ mFrameTimestamp = kCMTimeZero;
+ mFrameNum = 0;
+
+ started = 0;
+
+ mAsset = [[AVAsset assetWithURL:[NSURL fileURLWithPath: @(filename)]] retain];
+
+ if ( mAsset == nil ) {
+ fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
+ [localpool drain];
+ started = 0;
+ return;
+ }
+
+ mAssetTrack = [[mAsset tracksWithMediaType: AVMediaTypeVideo][0] retain];
+
+ if ( ! setupReadingAt(kCMTimeZero) ) {
+ fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
+ [localpool drain];
+ started = 0;
+ return;
+ }
+
+ started = 1;
+ [localpool drain];
+}
+
+CvCaptureFile::~CvCaptureFile() {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ free(mOutImagedata);
+ cvReleaseImage(&mOutImage);
+ cvReleaseImage(&mDeviceImage);
+ [mAssetReader release];
+ [mTrackOutput release];
+ [mAssetTrack release];
+ [mAsset release];
+ CVBufferRelease(mGrabbedPixels);
+ if ( mCurrentSampleBuffer ) {
+ CFRelease(mCurrentSampleBuffer);
+ }
+
+ [localpool drain];
+}
+
+bool CvCaptureFile::setupReadingAt(CMTime position) {
+ if (mAssetReader) {
+ if (mAssetReader.status == AVAssetReaderStatusReading) {
+ [mAssetReader cancelReading];
+ }
+ [mAssetReader release];
+ mAssetReader = nil;
+ }
+ if (mTrackOutput) {
+ [mTrackOutput release];
+ mTrackOutput = nil;
+ }
+
+ // Capture in a pixel format that can be converted efficiently to the output mode.
+ OSType pixelFormat;
+ if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) {
+ // For CV_CAP_MODE_BGR, read frames as BGRA (AV Foundation's YUV->RGB conversion is slightly faster than OpenCV's CV_YUV2BGR_YV12)
+ // kCVPixelFormatType_32ABGR is reportedly faster on OS X, but OpenCV doesn't have a CV_ABGR2BGR conversion.
+ // kCVPixelFormatType_24RGB is significanly slower than kCVPixelFormatType_32BGRA.
+ pixelFormat = kCVPixelFormatType_32BGRA;
+ mFormat = CV_8UC3;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ // For CV_CAP_MODE_GRAY, read frames as 420v (faster than 420f or 422 -- at least for H.264 files)
+ pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+ mFormat = CV_8UC1;
+ } else if (mMode == CV_CAP_MODE_YUYV) {
+ // For CV_CAP_MODE_YUYV, read frames directly as 422.
+ pixelFormat = kCVPixelFormatType_422YpCbCr8;
+ mFormat = CV_8UC2;
+ } else {
+ fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode);
+ return false;
+ }
+
+ NSDictionary *settings =
+ @{
+ (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+ };
+ mTrackOutput = [[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack: mAssetTrack
+ outputSettings: settings] retain];
+
+ if ( !mTrackOutput ) {
+ fprintf(stderr, "OpenCV: error in [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:outputSettings:]\n");
+ return false;
+ }
+
+ NSError *error = nil;
+ mAssetReader = [[AVAssetReader assetReaderWithAsset: mAsset
+ error: &error] retain];
+ if ( error ) {
+ fprintf(stderr, "OpenCV: error in [AVAssetReader assetReaderWithAsset:error:]\n");
+ NSLog(@"OpenCV: %@", error.localizedDescription);
+ return false;
+ }
+
+ mAssetReader.timeRange = CMTimeRangeMake(position, kCMTimePositiveInfinity);
+ mFrameTimestamp = position;
+ mFrameNum = round((mFrameTimestamp.value * mAssetTrack.nominalFrameRate) / double(mFrameTimestamp.timescale));
+ [mAssetReader addOutput: mTrackOutput];
+ [mAssetReader startReading];
+
+ return true;
+}
+
+int CvCaptureFile::didStart() {
+ return started;
+}
+
+bool CvCaptureFile::grabFrame() {
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ CVBufferRelease(mGrabbedPixels);
+ if ( mCurrentSampleBuffer ) {
+ CFRelease(mCurrentSampleBuffer);
+ }
+ mCurrentSampleBuffer = [mTrackOutput copyNextSampleBuffer];
+ mGrabbedPixels = CMSampleBufferGetImageBuffer(mCurrentSampleBuffer);
+ CVBufferRetain(mGrabbedPixels);
+ mFrameTimestamp = CMSampleBufferGetOutputPresentationTimeStamp(mCurrentSampleBuffer);
+ mFrameNum++;
+
+ bool isReading = (mAssetReader.status == AVAssetReaderStatusReading);
+ [localpool drain];
+ return isReading;
+}
+
+
+IplImage* CvCaptureFile::retrieveFramePixelBuffer() {
+ if ( ! mGrabbedPixels ) {
+ return 0;
+ }
+
+ NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+ CVPixelBufferLockBaseAddress(mGrabbedPixels, 0);
+ void *baseaddress;
+ size_t width, height, rowBytes;
+
+ OSType pixelFormat = CVPixelBufferGetPixelFormatType(mGrabbedPixels);
+
+ if (CVPixelBufferIsPlanar(mGrabbedPixels)) {
+ baseaddress = CVPixelBufferGetBaseAddressOfPlane(mGrabbedPixels, 0);
+ width = CVPixelBufferGetWidthOfPlane(mGrabbedPixels, 0);
+ height = CVPixelBufferGetHeightOfPlane(mGrabbedPixels, 0);
+ rowBytes = CVPixelBufferGetBytesPerRowOfPlane(mGrabbedPixels, 0);
+ } else {
+ baseaddress = CVPixelBufferGetBaseAddress(mGrabbedPixels);
+ width = CVPixelBufferGetWidth(mGrabbedPixels);
+ height = CVPixelBufferGetHeight(mGrabbedPixels);
+ rowBytes = CVPixelBufferGetBytesPerRow(mGrabbedPixels);
+ }
+
+ if ( rowBytes == 0 ) {
+ fprintf(stderr, "OpenCV: error: rowBytes == 0\n");
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ return 0;
+ }
+
+ // Output image paramaters.
+ int outChannels;
+ if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) {
+ outChannels = 3;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ outChannels = 1;
+ } else if (mMode == CV_CAP_MODE_YUYV) {
+ outChannels = 2;
+ } else {
+ fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode);
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ return 0;
+ }
+
+ if ( currSize != width*outChannels*height ) {
+ currSize = width*outChannels*height;
+ free(mOutImagedata);
+ mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+ }
+
+ // Build the header for the output image.
+ if (mOutImage == NULL) {
+ mOutImage = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, outChannels);
+ }
+ mOutImage->width = int(width);
+ mOutImage->height = int(height);
+ mOutImage->nChannels = outChannels;
+ mOutImage->depth = IPL_DEPTH_8U;
+ mOutImage->widthStep = int(width*outChannels);
+ mOutImage->imageData = reinterpret_cast<char *>(mOutImagedata);
+ mOutImage->imageSize = int(currSize);
+
+ // Device image paramaters and conversion code.
+ // (Not all of these conversions are used in production, but they were all tested to find the fastest options.)
+ int deviceChannels;
+ int cvtCode;
+
+ if ( pixelFormat == kCVPixelFormatType_32BGRA ) {
+ deviceChannels = 4;
+
+ if (mMode == CV_CAP_MODE_BGR) {
+ cvtCode = CV_BGRA2BGR;
+ } else if (mMode == CV_CAP_MODE_RGB) {
+ cvtCode = CV_BGRA2RGB;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ cvtCode = CV_BGRA2GRAY;
+ } else {
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+ return 0;
+ }
+ } else if ( pixelFormat == kCVPixelFormatType_24RGB ) {
+ deviceChannels = 3;
+
+ if (mMode == CV_CAP_MODE_BGR) {
+ cvtCode = CV_RGB2BGR;
+ } else if (mMode == CV_CAP_MODE_RGB) {
+ cvtCode = 0;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ cvtCode = CV_RGB2GRAY;
+ } else {
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+ return 0;
+ }
+ } else if ( pixelFormat == kCVPixelFormatType_422YpCbCr8 ) { // 422 (2vuy, UYVY)
+ deviceChannels = 2;
+
+ if (mMode == CV_CAP_MODE_BGR) {
+ cvtCode = CV_YUV2BGR_UYVY;
+ } else if (mMode == CV_CAP_MODE_RGB) {
+ cvtCode = CV_YUV2RGB_UYVY;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ cvtCode = CV_YUV2GRAY_UYVY;
+ } else if (mMode == CV_CAP_MODE_YUYV) {
+ cvtCode = -1; // Copy
+ } else {
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+ return 0;
+ }
+ } else if ( pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || // 420v
+ pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ) { // 420f
+ // cvCvtColor(CV_YUV2GRAY_420) is expecting a single buffer with both the Y plane and the CrCb planes.
+ // So, lie about the height of the buffer. cvCvtColor(CV_YUV2GRAY_420) will only read the first 2/3 of it.
+ height = height * 3 / 2;
+ deviceChannels = 1;
+
+ if (mMode == CV_CAP_MODE_BGR) {
+ cvtCode = CV_YUV2BGR_YV12;
+ } else if (mMode == CV_CAP_MODE_RGB) {
+ cvtCode = CV_YUV2RGB_YV12;
+ } else if (mMode == CV_CAP_MODE_GRAY) {
+ cvtCode = CV_YUV2GRAY_420;
+ } else {
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+ return 0;
+ }
+ } else {
+ fprintf(stderr, "OpenCV: unsupported pixel format 0x%08X\n", pixelFormat);
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+ CVBufferRelease(mGrabbedPixels);
+ mGrabbedPixels = NULL;
+ return 0;
+ }
+
+ // Build the header for the device image.
+ if (mDeviceImage == NULL) {
+ mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, deviceChannels);
+ }
+ mDeviceImage->width = int(width);
+ mDeviceImage->height = int(height);
+ mDeviceImage->nChannels = deviceChannels;
+ mDeviceImage->depth = IPL_DEPTH_8U;
+ mDeviceImage->widthStep = int(rowBytes);
+ mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+ mDeviceImage->imageSize = int(rowBytes*height);
+
+ // Convert the device image into the output image.
+ if (cvtCode == -1) {
+ // Copy.
+ cv::cvarrToMat(mDeviceImage).copyTo(cv::cvarrToMat(mOutImage));
+ } else {
+ cvCvtColor(mDeviceImage, mOutImage, cvtCode);
+ }
+
+
+ CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+
+ [localpool drain];
+
+ return mOutImage;
+}
+
+
+IplImage* CvCaptureFile::retrieveFrame(int) {
+ return retrieveFramePixelBuffer();
+}
+
+double CvCaptureFile::getProperty(int property_id) const{
+ if (mAsset == nil) return 0;
+
+ CMTime t;
+
+ switch (property_id) {
+ case CV_CAP_PROP_POS_MSEC:
+ return mFrameTimestamp.value * 1000.0 / mFrameTimestamp.timescale;
+ case CV_CAP_PROP_POS_FRAMES:
+ return mFrameNum;
+ case CV_CAP_PROP_POS_AVI_RATIO:
+ t = [mAsset duration];
+ return (mFrameTimestamp.value * t.timescale) / double(mFrameTimestamp.timescale * t.value);
+ case CV_CAP_PROP_FRAME_WIDTH:
+ return mAssetTrack.naturalSize.width;
+ case CV_CAP_PROP_FRAME_HEIGHT:
+ return mAssetTrack.naturalSize.height;
+ case CV_CAP_PROP_FPS:
+ return mAssetTrack.nominalFrameRate;
+ case CV_CAP_PROP_FRAME_COUNT:
+ t = [mAsset duration];
+ return round((t.value * mAssetTrack.nominalFrameRate) / double(t.timescale));
+ case CV_CAP_PROP_FORMAT:
+ return mFormat;
+ case CV_CAP_PROP_MODE:
+ return mMode;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+bool CvCaptureFile::setProperty(int property_id, double value) {
+ if (mAsset == nil) return false;
+
+ NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+ bool retval = false;
+ CMTime t;
+
+ switch (property_id) {
+ case CV_CAP_PROP_POS_MSEC:
+ t = mAsset.duration;
+ t.value = value * t.timescale / 1000;
+ setupReadingAt(t);
+ retval = true;
+ break;
+ case CV_CAP_PROP_POS_FRAMES:
+ setupReadingAt(CMTimeMake(value, mAssetTrack.nominalFrameRate));
+ retval = true;
+ break;
+ case CV_CAP_PROP_POS_AVI_RATIO:
+ t = mAsset.duration;
+ t.value = round(t.value * value);
+ setupReadingAt(t);
+ retval = true;
+ break;
+ case CV_CAP_PROP_MODE:
+ int mode;
+ mode = cvRound(value);
+ if (mMode == mode) {
+ retval = true;
+ } else {
+ switch (mode) {
+ case CV_CAP_MODE_BGR:
+ case CV_CAP_MODE_RGB:
+ case CV_CAP_MODE_GRAY:
+ case CV_CAP_MODE_YUYV:
+ mMode = mode;
+ setupReadingAt(mFrameTimestamp);
+ retval = true;
+ break;
+ default:
+ fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mode);
+ retval=false;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ [localpool drain];
+ return retval;
+}
+
+
+/*****************************************************************************
+ *
+ * CvVideoWriter_AVFoundation Implementation.
+ *
+ * CvVideoWriter_AVFoundation is the instantiation of a video output class.
+ *
+ *****************************************************************************/
+
+
+CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int fourcc,
+ double fps, CvSize frame_size,
+ int is_color) {
+
+ NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+
+ mFrameNum = 0;
+ mMovieFPS = fps;
+ movieSize = frame_size;
+ movieColor = is_color;
+ argbimage = cvCreateImage(movieSize, IPL_DEPTH_8U, 4);
+ path = [[[NSString stringWithCString:filename encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath] retain];
+
+
+ /*
+ AVFileTypeQuickTimeMovie
+ UTI for the QuickTime movie file format.
+ The value of this UTI is com.apple.quicktime-movie. Files are identified with the .mov and .qt extensions.
+
+ AVFileTypeMPEG4
+ UTI for the MPEG-4 file format.
+ The value of this UTI is public.mpeg-4. Files are identified with the .mp4 extension.
+
+ AVFileTypeAppleM4V
+ UTI for the iTunes video file format.
+ The value of this UTI is com.apple.mpeg-4-video. Files are identified with the .m4v extension.
+
+ AVFileType3GPP
+ UTI for the 3GPP file format.
+ The value of this UTI is public.3gpp. Files are identified with the .3gp, .3gpp, and .sdv extensions.
+ */
+
+ NSString *fileExt =[[[path pathExtension] lowercaseString] copy];
+ if ([fileExt isEqualToString:@"mov"] || [fileExt isEqualToString:@"qt"]){
+ fileType = [AVFileTypeQuickTimeMovie copy];
+ }else if ([fileExt isEqualToString:@"mp4"]){
+ fileType = [AVFileTypeMPEG4 copy];
+ }else if ([fileExt isEqualToString:@"m4v"]){
+ fileType = [AVFileTypeAppleM4V copy];
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+ }else if ([fileExt isEqualToString:@"3gp"] || [fileExt isEqualToString:@"3gpp"] || [fileExt isEqualToString:@"sdv"] ){
+ fileType = [AVFileType3GPP copy];
+#endif
+ } else{
+ fileType = [AVFileTypeMPEG4 copy]; //default mp4
+ }
+ [fileExt release];
+
+ char cc[5];
+ cc[0] = fourcc & 255;
+ cc[1] = (fourcc >> 8) & 255;
+ cc[2] = (fourcc >> 16) & 255;
+ cc[3] = (fourcc >> 24) & 255;
+ cc[4] = 0;
+ int cc2 = CV_FOURCC(cc[0], cc[1], cc[2], cc[3]);
+ if (cc2!=fourcc) {
+ fprintf(stderr, "OpenCV: Didn't properly encode FourCC. Expected 0x%08X but got 0x%08X.\n", fourcc, cc2);
+ //exception;
+ }
+
+ // Two codec supported AVVideoCodecH264 AVVideoCodecJPEG
+ // On iPhone 3G H264 is not supported.
+ if (fourcc == CV_FOURCC('J','P','E','G') || fourcc == CV_FOURCC('j','p','e','g') ||
+ fourcc == CV_FOURCC('M','J','P','G') || fourcc == CV_FOURCC('m','j','p','g') ){
+ codec = [AVVideoCodecJPEG copy]; // Use JPEG codec if specified, otherwise H264
+ }else if(fourcc == CV_FOURCC('H','2','6','4') || fourcc == CV_FOURCC('a','v','c','1')){
+ codec = [AVVideoCodecH264 copy];
+ }else{
+ codec = [AVVideoCodecH264 copy]; // default canonical H264.
+
+ }
+
+ //NSLog(@"Path: %@", path);
+
+ NSError *error = nil;
+
+
+ // Make sure the file does not already exist. Necessary to overwirte??
+ /*
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if ([fileManager fileExistsAtPath:path]){
+ [fileManager removeItemAtPath:path error:&error];
+ }
+ */
+
+ // Wire the writer:
+ // Supported file types:
+ // AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP
+
+ mMovieWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
+ fileType:fileType
+ error:&error];
+ //NSParameterAssert(mMovieWriter);
+
+ NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
+ codec, AVVideoCodecKey,
+ [NSNumber numberWithInt:movieSize.width], AVVideoWidthKey,
+ [NSNumber numberWithInt:movieSize.height], AVVideoHeightKey,
+ nil];
+
+ mMovieWriterInput = [[AVAssetWriterInput
+ assetWriterInputWithMediaType:AVMediaTypeVideo
+ outputSettings:videoSettings] retain];
+
+ //NSParameterAssert(mMovieWriterInput);
+ //NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]);
+
+ [mMovieWriter addInput:mMovieWriterInput];
+
+ mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:mMovieWriterInput sourcePixelBufferAttributes:nil];
+
+
+ //Start a session:
+ [mMovieWriter startWriting];
+ [mMovieWriter startSessionAtSourceTime:kCMTimeZero];
+
+
+ if(mMovieWriter.status == AVAssetWriterStatusFailed){
+ NSLog(@"AVF: AVAssetWriter status: %@", [mMovieWriter.error localizedDescription]);
+ // TODO: error handling, cleanup. Throw execption?
+ // return;
+ }
+
+ [localpool drain];
+}
+
+
+CvVideoWriter_AVFoundation::~CvVideoWriter_AVFoundation() {
+ NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+ [mMovieWriterInput markAsFinished];
+ [mMovieWriter finishWriting];
+ [mMovieWriter release];
+ [mMovieWriterInput release];
+ [mMovieWriterAdaptor release];
+ [path release];
+ [codec release];
+ [fileType release];
+ cvReleaseImage(&argbimage);
+
+ [localpool drain];
+
+}
+
+static void releaseCallback( void *releaseRefCon, const void * ) {
+ CFRelease((CFDataRef)releaseRefCon);
+}
+
+bool CvVideoWriter_AVFoundation::writeFrame(const IplImage* iplimage) {
+ NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+ // writer status check
+ if (mMovieWriter.status != AVAssetWriterStatusWriting ) {
+ NSLog(@"mMovieWriter.status: %d. Error: %@", (int)mMovieWriter.status, [mMovieWriter.error localizedDescription]);
+ [localpool drain];
+ return false;
+ }
+
+ // Make writeFrame() a blocking call.
+ while (![mMovieWriterInput isReadyForMoreMediaData]) {
+ fprintf(stderr, "OpenCV: AVF: waiting to write video data.\n");
+ // Sleep 1 msec.
+ usleep(1000);
+ }
+
+ BOOL success = FALSE;
+
+ if (iplimage->height!=movieSize.height || iplimage->width!=movieSize.width){
+ fprintf(stderr, "OpenCV: Frame size does not match video size.\n");
+ [localpool drain];
+ return false;
+ }
+
+ if (movieColor) {
+ //assert(iplimage->nChannels == 3);
+ cvCvtColor(iplimage, argbimage, CV_BGR2BGRA);
+ }else{
+ //assert(iplimage->nChannels == 1);
+ cvCvtColor(iplimage, argbimage, CV_GRAY2BGRA);
+ }
+ //IplImage -> CGImage conversion
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ NSData *nsData = [NSData dataWithBytes:argbimage->imageData length:argbimage->imageSize];
+ CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)nsData);
+ CGImageRef cgImage = CGImageCreate(argbimage->width, argbimage->height,
+ argbimage->depth, argbimage->depth * argbimage->nChannels, argbimage->widthStep,
+ colorSpace, kCGImageAlphaLast|kCGBitmapByteOrderDefault,
+ provider, NULL, false, kCGRenderingIntentDefault);
+
+ //CGImage -> CVPixelBufferRef coversion
+ CVPixelBufferRef pixelBuffer = NULL;
+ CFDataRef cfData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
+ int status = CVPixelBufferCreateWithBytes(NULL,
+ movieSize.width,
+ movieSize.height,
+ kCVPixelFormatType_32BGRA,
+ (void*)CFDataGetBytePtr(cfData),
+ CGImageGetBytesPerRow(cgImage),
+ &releaseCallback,
+ (void *)cfData,
+ NULL,
+ &pixelBuffer);
+ if(status == kCVReturnSuccess){
+ success = [mMovieWriterAdaptor appendPixelBuffer:pixelBuffer
+ withPresentationTime:CMTimeMake(mFrameNum, mMovieFPS)];
+ }
+
+ //cleanup
+ CVPixelBufferRelease(pixelBuffer);
+ CGImageRelease(cgImage);
+ CGDataProviderRelease(provider);
+ CGColorSpaceRelease(colorSpace);
+
+ [localpool drain];
+
+ if (success) {
+ mFrameNum ++;
+ //NSLog(@"Frame #%d", mFrameNum);
+ return true;
+ }else{
+ NSLog(@"Frame appendPixelBuffer failed.");
+ return false;
+ }
+
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/opencv.git
More information about the debian-science-commits
mailing list