|
|
|
@ -43,6 +43,7 @@ |
|
|
|
|
#include "precomp.hpp" |
|
|
|
|
#include "opencv2/imgproc.hpp" |
|
|
|
|
#include <stdio.h> |
|
|
|
|
#include <Availability.h> |
|
|
|
|
#import <AVFoundation/AVFoundation.h> |
|
|
|
|
|
|
|
|
|
/********************** Declaration of class headers ************************/ |
|
|
|
@ -177,12 +178,14 @@ private: |
|
|
|
|
|
|
|
|
|
class CvVideoWriter_AVFoundation : public CvVideoWriter { |
|
|
|
|
public: |
|
|
|
|
CvVideoWriter_AVFoundation(const char* filename, int fourcc, |
|
|
|
|
double fps, CvSize frame_size, |
|
|
|
|
int is_color=1); |
|
|
|
|
CvVideoWriter_AVFoundation(const std::string &filename, int fourcc, double fps, CvSize frame_size, int is_color); |
|
|
|
|
~CvVideoWriter_AVFoundation(); |
|
|
|
|
bool writeFrame(const IplImage* image) CV_OVERRIDE; |
|
|
|
|
int getCaptureDomain() const CV_OVERRIDE { return cv::CAP_AVFOUNDATION; } |
|
|
|
|
bool isOpened() const |
|
|
|
|
{ |
|
|
|
|
return is_good; |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
|
IplImage* argbimage; |
|
|
|
|
|
|
|
|
@ -197,6 +200,7 @@ class CvVideoWriter_AVFoundation : public CvVideoWriter { |
|
|
|
|
CvSize movieSize; |
|
|
|
|
int movieColor; |
|
|
|
|
unsigned long mFrameNum; |
|
|
|
|
bool is_good; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
/****************** Implementation of interface functions ********************/ |
|
|
|
@ -221,7 +225,13 @@ CvCapture* cvCreateCameraCapture_AVFoundation(int index ) { |
|
|
|
|
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); |
|
|
|
|
CvVideoWriter_AVFoundation* wrt = new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size, is_color); |
|
|
|
|
if (wrt->isOpened()) |
|
|
|
|
{ |
|
|
|
|
return wrt; |
|
|
|
|
} |
|
|
|
|
delete wrt; |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/********************** Implementation of Classes ****************************/ |
|
|
|
@ -305,6 +315,28 @@ void CvCaptureCAM::stopCaptureDevice() { |
|
|
|
|
int CvCaptureCAM::startCaptureDevice(int cameraNum) { |
|
|
|
|
NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; |
|
|
|
|
|
|
|
|
|
#if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 |
|
|
|
|
AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; |
|
|
|
|
if (status == AVAuthorizationStatusDenied) |
|
|
|
|
{ |
|
|
|
|
fprintf(stderr, "OpenCV: camera access has been denied. Either run 'tccutil reset Camera' " |
|
|
|
|
"command in same terminal to reset application authorization status, " |
|
|
|
|
"either modify 'System Preferences -> Security & Privacy -> Camera' " |
|
|
|
|
"settings for your application.\n"); |
|
|
|
|
[localpool drain]; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
else if (status != AVAuthorizationStatusAuthorized) |
|
|
|
|
{ |
|
|
|
|
fprintf(stderr, "OpenCV: not authorized to capture video (status %ld), requesting...\n", status); |
|
|
|
|
// TODO: doesn't work via ssh |
|
|
|
|
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL) { /* we don't care */}]; |
|
|
|
|
// we do not wait for completion |
|
|
|
|
[localpool drain]; |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
// get capture device |
|
|
|
|
NSArray *devices = [[AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo] |
|
|
|
|
arrayByAddingObjectsFromArray:[AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]]; |
|
|
|
@ -1096,38 +1128,20 @@ bool CvCaptureFile::setProperty(int property_id, double value) { |
|
|
|
|
*****************************************************************************/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int fourcc, |
|
|
|
|
double fps, CvSize frame_size, |
|
|
|
|
int is_color) { |
|
|
|
|
|
|
|
|
|
CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const std::string &filename, int fourcc, double fps, CvSize frame_size, int is_color) |
|
|
|
|
: argbimage(nil), mMovieWriter(nil), mMovieWriterInput(nil), mMovieWriterAdaptor(nil), path(nil), |
|
|
|
|
codec(nil), fileType(nil), mMovieFPS(fps), movieSize(frame_size), movieColor(is_color), mFrameNum(0), |
|
|
|
|
is_good(true) |
|
|
|
|
{ |
|
|
|
|
if (mMovieFPS <= 0 || movieSize.width <= 0 || movieSize.height <= 0) |
|
|
|
|
{ |
|
|
|
|
is_good = false; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
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. |
|
|
|
|
*/ |
|
|
|
|
path = [[[NSString stringWithUTF8String:filename.c_str()] stringByExpandingTildeInPath] retain]; |
|
|
|
|
|
|
|
|
|
NSString *fileExt =[[[path pathExtension] lowercaseString] copy]; |
|
|
|
|
if ([fileExt isEqualToString:@"mov"] || [fileExt isEqualToString:@"qt"]){ |
|
|
|
@ -1136,12 +1150,8 @@ CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int |
|
|
|
|
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 |
|
|
|
|
is_good = false; |
|
|
|
|
} |
|
|
|
|
[fileExt release]; |
|
|
|
|
|
|
|
|
@ -1153,8 +1163,7 @@ CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int |
|
|
|
|
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; |
|
|
|
|
is_good = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Two codec supported AVVideoCodecH264 AVVideoCodecJPEG |
|
|
|
@ -1165,59 +1174,59 @@ CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int |
|
|
|
|
}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. |
|
|
|
|
|
|
|
|
|
is_good = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//NSLog(@"Path: %@", path); |
|
|
|
|
|
|
|
|
|
NSError *error = nil; |
|
|
|
|
|
|
|
|
|
if (is_good) |
|
|
|
|
{ |
|
|
|
|
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 |
|
|
|
|
// Make sure the file does not already exist. Necessary to overwirte?? |
|
|
|
|
/* |
|
|
|
|
NSFileManager *fileManager = [NSFileManager defaultManager]; |
|
|
|
|
if ([fileManager fileExistsAtPath:path]){ |
|
|
|
|
[fileManager removeItemAtPath:path error:&error]; |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
mMovieWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path] |
|
|
|
|
fileType:fileType |
|
|
|
|
error:&error]; |
|
|
|
|
//NSParameterAssert(mMovieWriter); |
|
|
|
|
// Wire the writer: |
|
|
|
|
// Supported file types: |
|
|
|
|
// AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP |
|
|
|
|
|
|
|
|
|
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: |
|
|
|
|
codec, AVVideoCodecKey, |
|
|
|
|
[NSNumber numberWithInt:movieSize.width], AVVideoWidthKey, |
|
|
|
|
[NSNumber numberWithInt:movieSize.height], AVVideoHeightKey, |
|
|
|
|
nil]; |
|
|
|
|
mMovieWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path] |
|
|
|
|
fileType:fileType |
|
|
|
|
error:&error]; |
|
|
|
|
//NSParameterAssert(mMovieWriter); |
|
|
|
|
|
|
|
|
|
mMovieWriterInput = [[AVAssetWriterInput |
|
|
|
|
assetWriterInputWithMediaType:AVMediaTypeVideo |
|
|
|
|
outputSettings:videoSettings] retain]; |
|
|
|
|
NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: |
|
|
|
|
codec, AVVideoCodecKey, |
|
|
|
|
[NSNumber numberWithInt:movieSize.width], AVVideoWidthKey, |
|
|
|
|
[NSNumber numberWithInt:movieSize.height], AVVideoHeightKey, |
|
|
|
|
nil]; |
|
|
|
|
|
|
|
|
|
//NSParameterAssert(mMovieWriterInput); |
|
|
|
|
//NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]); |
|
|
|
|
mMovieWriterInput = [[AVAssetWriterInput |
|
|
|
|
assetWriterInputWithMediaType:AVMediaTypeVideo |
|
|
|
|
outputSettings:videoSettings] retain]; |
|
|
|
|
|
|
|
|
|
[mMovieWriter addInput:mMovieWriterInput]; |
|
|
|
|
//NSParameterAssert(mMovieWriterInput); |
|
|
|
|
//NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]); |
|
|
|
|
|
|
|
|
|
mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:mMovieWriterInput sourcePixelBufferAttributes:nil]; |
|
|
|
|
[mMovieWriter addInput:mMovieWriterInput]; |
|
|
|
|
|
|
|
|
|
mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:mMovieWriterInput sourcePixelBufferAttributes:nil]; |
|
|
|
|
|
|
|
|
|
//Start a session: |
|
|
|
|
[mMovieWriter startWriting]; |
|
|
|
|
[mMovieWriter startSessionAtSourceTime:kCMTimeZero]; |
|
|
|
|
|
|
|
|
|
//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; |
|
|
|
|
if(mMovieWriter.status == AVAssetWriterStatusFailed){ |
|
|
|
|
NSLog(@"AVF: AVAssetWriter status: %@", [mMovieWriter.error localizedDescription]); |
|
|
|
|
is_good = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
[localpool drain]; |
|
|
|
@ -1227,15 +1236,22 @@ CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int |
|
|
|
|
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); |
|
|
|
|
if (mMovieWriterInput && mMovieWriter && mMovieWriterAdaptor) |
|
|
|
|
{ |
|
|
|
|
[mMovieWriterInput markAsFinished]; |
|
|
|
|
[mMovieWriter finishWriting]; |
|
|
|
|
[mMovieWriter release]; |
|
|
|
|
[mMovieWriterInput release]; |
|
|
|
|
[mMovieWriterAdaptor release]; |
|
|
|
|
} |
|
|
|
|
if (path) |
|
|
|
|
[path release]; |
|
|
|
|
if (codec) |
|
|
|
|
[codec release]; |
|
|
|
|
if (fileType) |
|
|
|
|
[fileType release]; |
|
|
|
|
if (argbimage) |
|
|
|
|
cvReleaseImage(&argbimage); |
|
|
|
|
|
|
|
|
|
[localpool drain]; |
|
|
|
|
|
|
|
|
|