@@ -1155,228 +1155,198 @@ -(bool) updateImage {
11551155double fps,const cv::Size& frame_size,
11561156int is_color) {
11571157
1158- NSAutoreleasePool * localpool = [[NSAutoreleasePool alloc ]init ];
1159-
1160-
1161- frameCount =0 ;
1162- movieFPS = fps;
1163- movieSize = frame_size;
1164- movieColor = is_color;
1165- argbimage =cv::Mat (movieSize, CV_8UC4);
1166- path = [[[NSString stringWithCString: filenameencoding: NSASCIIStringEncoding]stringByExpandingTildeInPath ]retain ];
1167-
1158+ @autoreleasepool {
1159+ frameCount =0 ;
1160+ movieFPS = fps;
1161+ movieSize = frame_size;
1162+ movieColor = is_color;
1163+ argbimage =cv::Mat (movieSize, CV_8UC4);
1164+ path = [[[NSString stringWithCString: filenameencoding: NSASCIIStringEncoding]stringByExpandingTildeInPath ]retain ];
11681165
1169- /*
1170- AVFileTypeQuickTimeMovie
1171- UTI for the QuickTime movie file format.
1172- The value of this UTI is com.apple.quicktime-movie. Files are identified with the .mov and .qt extensions.
1166+ /*
1167+ AVFileTypeQuickTimeMovie
1168+ UTI for the QuickTime movie file format.
1169+ The value of this UTI is com.apple.quicktime-movie. Files are identified with the .mov and .qt extensions.
11731170
1174- AVFileTypeMPEG4
1175- UTI for the MPEG-4 file format.
1176- The value of this UTI is public.mpeg-4. Files are identified with the .mp4 extension.
1171+ AVFileTypeMPEG4
1172+ UTI for the MPEG-4 file format.
1173+ The value of this UTI is public.mpeg-4. Files are identified with the .mp4 extension.
11771174
1178- AVFileTypeAppleM4V
1179- UTI for the iTunes video file format.
1180- The value of this UTI is com.apple.mpeg-4-video. Files are identified with the .m4v extension.
1175+ AVFileTypeAppleM4V
1176+ UTI for the iTunes video file format.
1177+ The value of this UTI is com.apple.mpeg-4-video. Files are identified with the .m4v extension.
11811178
1182- AVFileType3GPP
1183- UTI for the 3GPP file format.
1184- The value of this UTI is public.3gpp. Files are identified with the .3gp, .3gpp, and .sdv extensions.
1185- */
1179+ AVFileType3GPP
1180+ UTI for the 3GPP file format.
1181+ The value of this UTI is public.3gpp. Files are identified with the .3gp, .3gpp, and .sdv extensions.
1182+ */
11861183
1187- NSString *fileExt =[[[pathpathExtension ]lowercaseString ]copy ];
1188- if ([fileExtisEqualToString: @" mov" ] || [fileExtisEqualToString: @" qt" ]){
1189- fileType = [AVFileTypeQuickTimeMoviecopy ];
1190- } else if ([fileExtisEqualToString: @" mp4" ]){
1191- fileType = [AVFileTypeMPEG4copy ];
1192- } else if ([fileExtisEqualToString: @" m4v" ]){
1193- fileType = [AVFileTypeAppleM4Vcopy ];
1184+ NSString *fileExt = [[[pathpathExtension ]lowercaseString ]copy ];
1185+ if ([fileExtisEqualToString: @" mov" ] || [fileExtisEqualToString: @" qt" ]) {
1186+ fileType = [AVFileTypeQuickTimeMoviecopy ];
1187+ } else if ([fileExtisEqualToString: @" mp4" ]) {
1188+ fileType = [AVFileTypeMPEG4copy ];
1189+ } else if ([fileExtisEqualToString: @" m4v" ]) {
1190+ fileType = [AVFileTypeAppleM4Vcopy ];
11941191#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
1195- } else if ([fileExtisEqualToString: @" 3gp" ] || [fileExtisEqualToString: @" 3gpp" ] || [fileExtisEqualToString: @" sdv" ] ) {
1196- fileType = [AVFileType3GPPcopy ];
1192+ } else if ([fileExtisEqualToString: @" 3gp" ] || [fileExtisEqualToString: @" 3gpp" ] || [fileExtisEqualToString: @" sdv" ]) {
1193+ fileType = [AVFileType3GPPcopy ];
11971194#endif
1198- }else {
1199- fileType = [AVFileTypeMPEG4copy ];// default mp4
1200- }
1201- [fileExtrelease ];
1202-
1203- char cc[5 ];
1204- cc[0 ] = fourcc &255 ;
1205- cc[1 ] = (fourcc >>8 ) &255 ;
1206- cc[2 ] = (fourcc >>16 ) &255 ;
1207- cc[3 ] = (fourcc >>24 ) &255 ;
1208- cc[4 ] =0 ;
1209- int cc2 =CV_FOURCC (cc[0 ], cc[1 ], cc[2 ], cc[3 ]);
1210- if (cc2!=fourcc) {
1211- std::cout <<" WARNING: Didn't properly encode FourCC. Expected" << fourcc
1212- <<" but got" << cc2 <<" ." << std::endl;
1213- // exception;
1214- }
1195+ }else {
1196+ fileType = [AVFileTypeMPEG4copy ];// default mp4
1197+ }
1198+ [fileExtrelease ];
1199+
1200+ char cc[5 ];
1201+ cc[0 ] = fourcc &255 ;
1202+ cc[1 ] = (fourcc >>8 ) &255 ;
1203+ cc[2 ] = (fourcc >>16 ) &255 ;
1204+ cc[3 ] = (fourcc >>24 ) &255 ;
1205+ cc[4 ] =0 ;
1206+ int cc2 =CV_FOURCC (cc[0 ], cc[1 ], cc[2 ], cc[3 ]);
1207+ if (cc2 != fourcc) {
1208+ std::cout <<" WARNING: Didn't properly encode FourCC. Expected" << fourcc
1209+ <<" but got" << cc2 <<" ." << std::endl;
1210+ }
12151211
1216- // Three codec supported AVVideoCodecTypeH264 AVVideoCodecTypeJPEG AVVideoCodecTypeHEVC
1217- // On iPhone 3G H264 is not supported.
1218- if (fourcc ==CV_FOURCC (' J' ,' P' ,' E' ,' G' ) || fourcc ==CV_FOURCC (' j' ,' p' ,' e' ,' g' ) ||
1219- fourcc ==CV_FOURCC (' M' ,' J' ,' P' ,' G' ) || fourcc ==CV_FOURCC (' m' ,' j' ,' p' ,' g' )){
1220- codec = [AVVideoCodecTypeJPEGcopy ];// Use JPEG codec if specified, otherwise H264
1221- } else if (fourcc ==CV_FOURCC (' H' ,' 2' ,' 6' ,' 4' ) || fourcc ==CV_FOURCC (' a' ,' v' ,' c' ,' 1' )){
1222- codec = [AVVideoCodecTypeH264copy ];
1212+ // Three codec supported AVVideoCodecTypeH264 AVVideoCodecTypeJPEG AVVideoCodecTypeHEVC
1213+ // On iPhone 3G H264 is not supported.
1214+ if (fourcc ==CV_FOURCC (' J' ,' P' ,' E' ,' G' ) || fourcc ==CV_FOURCC (' j' ,' p' ,' e' ,' g' ) ||
1215+ fourcc ==CV_FOURCC (' M' ,' J' ,' P' ,' G' ) || fourcc ==CV_FOURCC (' m' ,' j' ,' p' ,' g' )) {
1216+ codec = [AVVideoCodecTypeJPEGcopy ];// Use JPEG codec if specified, otherwise H264
1217+ } else if (fourcc ==CV_FOURCC (' H' ,' 2' ,' 6' ,' 4' ) || fourcc ==CV_FOURCC (' a' ,' v' ,' c' ,' 1' )) {
1218+ codec = [AVVideoCodecTypeH264copy ];
12231219// Available since iOS 11
12241220#if TARGET_OS_VISION || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000)
1225- }else if (fourcc ==CV_FOURCC (' H' ,' 2' ,' 6' ,' 5' ) || fourcc ==CV_FOURCC (' h' ,' v' ,' c' ,' 1' ) ||
1226- fourcc ==CV_FOURCC (' H' ,' E' ,' V' ,' C' ) || fourcc ==CV_FOURCC (' h' ,' e' ,' v' ,' c' )){
1227- if (@available (iOS11 , *)) {
1228- codec = [AVVideoCodecTypeHEVCcopy ];
1221+ }else if (fourcc ==CV_FOURCC (' H' ,' 2' ,' 6' ,' 5' ) || fourcc ==CV_FOURCC (' h' ,' v' ,' c' ,' 1' ) ||
1222+ fourcc ==CV_FOURCC (' H' ,' E' ,' V' ,' C' ) || fourcc ==CV_FOURCC (' h' ,' e' ,' v' ,' c' )) {
1223+ if (@available (iOS11 , *)) {
1224+ codec = [AVVideoCodecTypeHEVCcopy ];
1225+ }else {
1226+ codec = [AVVideoCodecTypeH264copy ];
1227+ }
1228+ #endif
12291229 }else {
1230- codec = [AVVideoCodecTypeH264copy ];
1230+ codec = [AVVideoCodecTypeH264copy ];// default canonical H264.
12311231 }
1232- #endif
1233- }else {
1234- codec = [AVVideoCodecTypeH264copy ];// default canonical H264.
1235- }
1236-
1237- // NSLog(@"Path: %@", path);
12381232
1239- NSError *error =nil ;
1233+ NSError *error =nil ;
12401234
1235+ // Wire the writer:
1236+ // Supported file types:
1237+ // AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP
12411238
1242- // Make sure the file does not already exist. Necessary to overwrite??
1243- /*
1244- NSFileManager *fileManager = [NSFileManager defaultManager];
1245- if ([fileManager fileExistsAtPath:path]){
1246- [fileManager removeItemAtPath:path error:&error];
1247- }
1248- */
1239+ mMovieWriter = [[AVAssetWriteralloc ]initWithURL: [NSURL fileURLWithPath: path]
1240+ fileType: fileType
1241+ error: &error];
12491242
1250- // Wire the writer:
1251- // Supported file types:
1252- // AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP
1243+ NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
1244+ codec, AVVideoCodecKey,
1245+ [NSNumber numberWithInt: movieSize.width], AVVideoWidthKey,
1246+ [NSNumber numberWithInt: movieSize.height], AVVideoHeightKey,
1247+ nil ];
12531248
1254- mMovieWriter = [[AVAssetWriteralloc ]initWithURL: [NSURL fileURLWithPath: path]
1255- fileType: fileType
1256- error: &error];
1257- // NSParameterAssert(mMovieWriter);
1249+ mMovieWriterInput = [[AVAssetWriterInput
1250+ assetWriterInputWithMediaType: AVMediaTypeVideo
1251+ outputSettings: videoSettings]retain ];
12581252
1259- NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
1260- codec, AVVideoCodecKey,
1261- [NSNumber numberWithInt: movieSize.width], AVVideoWidthKey,
1262- [NSNumber numberWithInt: movieSize.height], AVVideoHeightKey,
1263- nil ];
1253+ [mMovieWriteraddInput: mMovieWriterInput ];
12641254
1265- mMovieWriterInput = [[AVAssetWriterInput
1266- assetWriterInputWithMediaType: AVMediaTypeVideo
1267- outputSettings: videoSettings]retain ];
1255+ mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptoralloc ]initWithAssetWriterInput: mMovieWriterInput sourcePixelBufferAttributes: nil ];
12681256
1269- // NSParameterAssert(mMovieWriterInput);
1270- // NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]);
1257+ // Start a session:
1258+ [mMovieWriterstartWriting ];
1259+ [mMovieWriterstartSessionAtSourceTime: kCMTimeZero ];
12711260
1272- [mMovieWriteraddInput: mMovieWriterInput ];
1273-
1274- mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptoralloc ]initWithAssetWriterInput: mMovieWriterInput sourcePixelBufferAttributes: nil ];
1275-
1276-
1277- // Start a session:
1278- [mMovieWriterstartWriting ];
1279- [mMovieWriterstartSessionAtSourceTime: kCMTimeZero ];
1280-
1281-
1282- if (mMovieWriter .status == AVAssetWriterStatusFailed){
1283- NSLog (@" %@ " , [mMovieWriter.errorlocalizedDescription ]);
1284- // TODO: error handling, cleanup. Throw exception?
1285- // return;
1261+ if (mMovieWriter .status == AVAssetWriterStatusFailed) {
1262+ NSLog (@" %@ " , [mMovieWriter.errorlocalizedDescription ]);
1263+ // TODO: error handling, cleanup. Throw exception?
1264+ }
12861265 }
1287-
1288- [localpooldrain ];
12891266}
12901267
12911268
12921269CvVideoWriter_AVFoundation::~CvVideoWriter_AVFoundation () {
1293- NSAutoreleasePool * localpool = [[ NSAutoreleasePool alloc ] init ];
1294-
1295- [mMovieWriterInput markAsFinished ];
1296- [mMovieWriter finishWritingWithCompletionHandler: ^() {
1297- [mMovieWriterrelease ];
1298- [mMovieWriterInputrelease ];
1299- [mMovieWriterAdaptorrelease ];
1300- [pathrelease ];
1301- [codecrelease ];
1302- [fileTyperelease ];
1303- argbimage.release ();
1304-
1305- [localpool drain ];
1306- }];
1270+ @autoreleasepool {
1271+ [mMovieWriterInput markAsFinished ];
1272+ [mMovieWriter finishWritingWithCompletionHandler: ^() {
1273+ @autoreleasepool {
1274+ [mMovieWriterrelease ];
1275+ [mMovieWriterInputrelease ];
1276+ [mMovieWriterAdaptorrelease ];
1277+ [pathrelease ];
1278+ [codecrelease ];
1279+ [fileTyperelease ];
1280+ argbimage.release ();
1281+ }
1282+ } ];
1283+ }
13071284}
13081285
13091286void CvVideoWriter_AVFoundation::write (cv::InputArray image) {
1310- NSAutoreleasePool * localpool = [[NSAutoreleasePool alloc ]init ];
1311-
1312- // writer status check
1313- if (![mMovieWriterInputisReadyForMoreMediaData ] ||mMovieWriter .status != AVAssetWriterStatusWriting ) {
1314- NSLog (@" [mMovieWriterInput isReadyForMoreMediaData] Not ready for media data or ..." );
1315- NSLog (@" mMovieWriter.status:%d . Error:%@ " , (int )mMovieWriter.status, [mMovieWriter.error localizedDescription]);
1316- [localpooldrain ];
1317- return ;
1318- }
1287+ @autoreleasepool {
1288+ // writer status check
1289+ if (![mMovieWriterInputisReadyForMoreMediaData ] ||mMovieWriter .status != AVAssetWriterStatusWriting) {
1290+ NSLog (@" [mMovieWriterInput isReadyForMoreMediaData] Not ready for media data or ..." );
1291+ NSLog (@" mMovieWriter.status:%d . Error:%@ " , (int )mMovieWriter.status, [mMovieWriter.error localizedDescription]);
1292+ return ;
1293+ }
13191294
1320- BOOL success =FALSE ;
1295+ BOOL success =FALSE ;
13211296
1322- if (image.size ().height !=movieSize.height || image.size ().width !=movieSize.width ){
1323- std::cout<<" Frame size does not match video size." <<std::endl;
1324- [localpooldrain ];
1325- return ;
1326- }
1297+ if (image.size ().height != movieSize.height || image.size ().width != movieSize.width ) {
1298+ std::cout <<" Frame size does not match video size." << std::endl;
1299+ return ;
1300+ }
13271301
1328- if (movieColor) {
1329- // assert(image->nChannels == 3);
1330- cv::cvtColor (image, argbimage, cv::COLOR_BGR2BGRA);
1331- }else {
1332- // assert(image->nChannels == 1);
1333- cv::cvtColor (image, argbimage, cv::COLOR_GRAY2BGRA);
1334- }
1335- // IplImage -> CGImage conversion
1336- CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceRGB ();
1337- NSData *nsData = [NSData dataWithBytes: argbimage.datalength: argbimage.total () * argbimage.elemSize ()];
1338- CGDataProviderRef provider =CGDataProviderCreateWithCFData ((CFDataRef)nsData);
1339- CGImageRef cgImage =CGImageCreate (argbimage.size ().width , argbimage.size ().height ,
1340- 8 ,32 , argbimage.step [0 ],
1341- colorSpace,kCGImageAlphaLast |kCGBitmapByteOrderDefault ,
1342- provider,NULL ,false ,kCGRenderingIntentDefault );
1343-
1344- // CGImage -> CVPixelBufferRef conversion
1345- CVPixelBufferRef pixelBuffer =NULL ;
1346- CFDataRef cfData =CGDataProviderCopyData (CGImageGetDataProvider (cgImage));
1347- int status =CVPixelBufferCreateWithBytes (NULL ,
1348- movieSize.width ,
1349- movieSize.height ,
1350- kCVPixelFormatType_32BGRA ,
1351- (void *)CFDataGetBytePtr (cfData),
1352- CGImageGetBytesPerRow (cgImage),
1353- NULL ,
1354- 0 ,
1355- NULL ,
1356- &pixelBuffer);
1357- if (status ==kCVReturnSuccess ){
1358- success = [mMovieWriterAdaptorappendPixelBuffer: pixelBuffer
1359- withPresentationTime: CMTimeMake (frameCount, movieFPS)];
1360- }
1302+ if (movieColor) {
1303+ cv::cvtColor (image, argbimage, cv::COLOR_BGR2BGRA);
1304+ }else {
1305+ cv::cvtColor (image, argbimage, cv::COLOR_GRAY2BGRA);
1306+ }
13611307
1362- // cleanup
1363- CFRelease (cfData);
1364- CVPixelBufferRelease (pixelBuffer);
1365- CGImageRelease (cgImage);
1366- CGDataProviderRelease (provider);
1367- CGColorSpaceRelease (colorSpace);
1308+ // IplImage -> CGImage conversion
1309+ CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceRGB ();
1310+ NSData *nsData = [NSData dataWithBytes: argbimage.datalength: argbimage.total () * argbimage.elemSize ()];
1311+ CGDataProviderRef provider =CGDataProviderCreateWithCFData ((CFDataRef)nsData);
1312+ CGImageRef cgImage =CGImageCreate (argbimage.size ().width , argbimage.size ().height ,
1313+ 8 ,32 , argbimage.step [0 ],
1314+ colorSpace,kCGImageAlphaLast |kCGBitmapByteOrderDefault ,
1315+ provider,NULL ,false ,kCGRenderingIntentDefault );
1316+
1317+ // CGImage -> CVPixelBufferRef conversion
1318+ CVPixelBufferRef pixelBuffer =NULL ;
1319+ CFDataRef cfData =CGDataProviderCopyData (CGImageGetDataProvider (cgImage));
1320+ int status =CVPixelBufferCreateWithBytes (NULL ,
1321+ movieSize.width ,
1322+ movieSize.height ,
1323+ kCVPixelFormatType_32BGRA ,
1324+ (void *)CFDataGetBytePtr (cfData),
1325+ CGImageGetBytesPerRow (cgImage),
1326+ NULL ,
1327+ 0 ,
1328+ NULL ,
1329+ &pixelBuffer);
1330+ if (status ==kCVReturnSuccess ) {
1331+ success = [mMovieWriterAdaptorappendPixelBuffer: pixelBuffer
1332+ withPresentationTime: CMTimeMake (frameCount, movieFPS)];
1333+ }
13681334
1369- [localpooldrain ];
1335+ // cleanup
1336+ CFRelease (cfData);
1337+ CVPixelBufferRelease (pixelBuffer);
1338+ CGImageRelease (cgImage);
1339+ CGDataProviderRelease (provider);
1340+ CGColorSpaceRelease (colorSpace);
13701341
1371- if (success) {
1372- frameCount ++;
1373- // NSLog(@"Frame #%d", frameCount) ;
1374- return ;
1375- } else {
1376- NSLog ( @" Frame appendPixelBuffer failed. " ) ;
1377- return ;
1342+ if (success) {
1343+ frameCount ++;
1344+ return ;
1345+ } else {
1346+ NSLog ( @" Frame appendPixelBuffer failed. " );
1347+ return ;
1348+ }
13781349 }
1379-
13801350}
13811351
1382- #pragma clang diagnostic pop
1352+ #pragma clang diagnostic pop