cleanup Objective-C code from C++
This commit is contained in:
172
src/app.cpp
172
src/app.cpp
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
|
#include "objc_utils.h"
|
||||||
#endif
|
#endif
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
@@ -713,17 +714,7 @@ void App::rec_clear()
|
|||||||
{
|
{
|
||||||
rec_stop();
|
rec_stop();
|
||||||
#if defined(__IOS__) || defined(__OSX__)
|
#if defined(__IOS__) || defined(__OSX__)
|
||||||
NSString *path = [NSString stringWithUTF8String:rec_path.c_str()];
|
delete_all_files_in_path(rec_path);
|
||||||
NSDirectoryEnumerator* en = [[NSFileManager defaultManager] enumeratorAtPath:path];
|
|
||||||
NSError* err = nil;
|
|
||||||
BOOL res;
|
|
||||||
NSString* file;
|
|
||||||
while (file = [en nextObject])
|
|
||||||
{
|
|
||||||
NSString* file_path = [path stringByAppendingPathComponent:file];
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:file_path error:nil];
|
|
||||||
NSLog(@"delete: %@", file_path);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
rec_count = 0;
|
rec_count = 0;
|
||||||
update_rec_frames();
|
update_rec_frames();
|
||||||
@@ -760,11 +751,6 @@ void App::rec_stop()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stillImageDataReleaseCallback(void *releaseRefCon, const void *baseAddress)
|
|
||||||
{
|
|
||||||
free((void *)baseAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
void App::rec_export(std::string path)
|
void App::rec_export(std::string path)
|
||||||
{
|
{
|
||||||
int progress = 0;
|
int progress = 0;
|
||||||
@@ -774,157 +760,9 @@ void App::rec_export(std::string path)
|
|||||||
pb->m_title->set_text("Exporting MP4 movie");
|
pb->m_title->set_text("Exporting MP4 movie");
|
||||||
|
|
||||||
#if defined(__IOS__) || defined(__OSX__)
|
#if defined(__IOS__) || defined(__OSX__)
|
||||||
NSString* mov_path = [NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()];
|
export_mp4(rec_path, width, height, rec_count, ^(float) {
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:mov_path])
|
pb->m_progress->SetWidthP((float)progress / tot * 100.f);
|
||||||
{
|
});
|
||||||
NSLog(@"remove existing mp4");
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:mov_path error:nil];
|
|
||||||
}
|
|
||||||
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()]];
|
|
||||||
AVAssetWriter* writer = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeMPEG4 error:nil];
|
|
||||||
writer.shouldOptimizeForNetworkUse = NO;
|
|
||||||
NSDictionary *videoCompressionSettings = @{
|
|
||||||
AVVideoCodecKey : AVVideoCodecH264,
|
|
||||||
AVVideoWidthKey : @(width),
|
|
||||||
AVVideoHeightKey : @(height),
|
|
||||||
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(8<<20) }
|
|
||||||
};
|
|
||||||
if (![writer canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo])
|
|
||||||
{
|
|
||||||
NSLog(@"Couldn't add asset writer video input.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AVAssetWriterInput* input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
|
|
||||||
outputSettings:videoCompressionSettings
|
|
||||||
sourceFormatHint:nil];
|
|
||||||
input.expectsMediaDataInRealTime = YES;
|
|
||||||
|
|
||||||
NSDictionary *adaptorDict = @{
|
|
||||||
(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
|
|
||||||
(id)kCVPixelBufferWidthKey : @(width),
|
|
||||||
(id)kCVPixelBufferHeightKey : @(height)
|
|
||||||
};
|
|
||||||
|
|
||||||
AVAssetWriterInputPixelBufferAdaptor* _pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
|
|
||||||
initWithAssetWriterInput:input
|
|
||||||
sourcePixelBufferAttributes:adaptorDict];
|
|
||||||
|
|
||||||
|
|
||||||
// Add asset writer input to asset writer
|
|
||||||
if (![writer canAddInput:input]) {
|
|
||||||
NSLog(@"Couldn't add input to writer.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
[writer addInput:input];
|
|
||||||
|
|
||||||
CMTime t;
|
|
||||||
t.timescale = 30;
|
|
||||||
t.flags = kCMTimeFlags_Valid;
|
|
||||||
t.epoch = 0;
|
|
||||||
t.value = 0;
|
|
||||||
//[writer startSessionAtSourceTime:t];
|
|
||||||
|
|
||||||
CVPixelBufferRef buff = NULL;
|
|
||||||
uint8_t* data = (uint8_t*)calloc(1, width * height * 4);
|
|
||||||
CVPixelBufferCreateWithBytes(kCFAllocatorDefault, width, height, kCVPixelFormatType_32RGBA, data,
|
|
||||||
width * 4, stillImageDataReleaseCallback, nil, nil, &buff);
|
|
||||||
OSStatus err = CVPixelBufferPoolCreatePixelBuffer(nil, _pixelBufferAdaptor.pixelBufferPool, &buff);
|
|
||||||
|
|
||||||
|
|
||||||
if (writer.status == AVAssetWriterStatusUnknown)
|
|
||||||
{
|
|
||||||
// If the asset writer status is unknown, implies writing hasn't started yet, hence start writing with start time as the buffer's presentation timestamp
|
|
||||||
if ([writer startWriting])
|
|
||||||
{
|
|
||||||
[writer startSessionAtSourceTime:t];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer.status == AVAssetWriterStatusWriting)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < tot; i++)
|
|
||||||
{
|
|
||||||
// If the asset writer status is writing, append sample buffer to its corresponding asset writer input
|
|
||||||
if (input.readyForMoreMediaData)
|
|
||||||
{
|
|
||||||
char path[256];
|
|
||||||
snprintf(path, sizeof(path), "%s/%04d.jpg", rec_path.c_str(), i);
|
|
||||||
NSString* img_path = [NSString stringWithUTF8String:path];
|
|
||||||
NSLog(@"frame: %@", img_path);
|
|
||||||
#if __OSX__
|
|
||||||
NSImage *image = [[NSImage alloc] initWithContentsOfFile:img_path];
|
|
||||||
if (!image)
|
|
||||||
break;
|
|
||||||
NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);
|
|
||||||
CGImageRef cgImage = [image CGImageForProposedRect:&imageRect context:NULL hints:nil];
|
|
||||||
#elif __IOS__
|
|
||||||
UIImage* image = [UIImage imageNamed:img_path];
|
|
||||||
if (!image)
|
|
||||||
break;
|
|
||||||
CGImageRef cgImage = image.CGImage;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
||||||
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
|
|
||||||
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
|
|
||||||
CGSize sz = image.size;
|
|
||||||
CVPixelBufferRef pxbuffer = NULL;
|
|
||||||
{
|
|
||||||
CGImageRef image = cgImage;
|
|
||||||
CGSize size = sz;
|
|
||||||
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
|
|
||||||
// CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pxbuffer);
|
|
||||||
|
|
||||||
//NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
|
|
||||||
|
|
||||||
CVPixelBufferLockBaseAddress(pxbuffer, 0);
|
|
||||||
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
|
|
||||||
//NSParameterAssert(pxdata != NULL);
|
|
||||||
|
|
||||||
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
|
|
||||||
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
|
|
||||||
//NSParameterAssert(context);
|
|
||||||
|
|
||||||
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
|
|
||||||
|
|
||||||
CGColorSpaceRelease(rgbColorSpace);
|
|
||||||
CGContextRelease(context);
|
|
||||||
|
|
||||||
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
t.value = i;
|
|
||||||
if (![_pixelBufferAdaptor appendPixelBuffer:pxbuffer withPresentationTime:t])
|
|
||||||
{
|
|
||||||
NSLog(@"error %@", [writer.error localizedFailureReason]);
|
|
||||||
}
|
|
||||||
CFRelease(pxbuffer);
|
|
||||||
|
|
||||||
progress++;
|
|
||||||
pb->m_progress->SetWidthP((float)progress / tot * 100.f);
|
|
||||||
async_update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[input markAsFinished];
|
|
||||||
[writer finishWritingWithCompletionHandler:^{
|
|
||||||
NSString* path = [NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()];
|
|
||||||
NSLog(@"saved video %@", path);
|
|
||||||
#if __IOS__
|
|
||||||
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path))
|
|
||||||
{
|
|
||||||
NSLog(@"saving to camera roll");
|
|
||||||
UISaveVideoAtPathToSavedPhotosAlbum(path, nil, nil, nil);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writer.status == AVAssetWriterStatusFailed)
|
|
||||||
{
|
|
||||||
NSLog(@"failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pb->destroy();
|
pb->destroy();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
#import <Photos/Photos.h>
|
#import "objc_utils.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -1863,18 +1863,7 @@ void Canvas::export_equirectangular_thread(std::string file_path)
|
|||||||
|
|
||||||
//int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride());
|
//int ret = stbi_write_png(name, m_latlong.getWidth(), m_latlong.getHeight(), 4, latlong_data.get(), m_latlong.stride());
|
||||||
#ifdef __IOS__
|
#ifdef __IOS__
|
||||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
save_image_library(file_path);
|
||||||
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:file_path.c_str()]];
|
|
||||||
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
|
|
||||||
changeRequest.creationDate = [NSDate date];
|
|
||||||
} completionHandler:^(BOOL success, NSError *error) {
|
|
||||||
if (success) {
|
|
||||||
NSLog(@"successfully saved");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSLog(@"error saving to photos: %@", error);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
App::I->render_task_async([id=cube_id]
|
App::I->render_task_async([id=cube_id]
|
||||||
@@ -2261,18 +2250,7 @@ void Canvas::export_cubes()
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __IOS__
|
#ifdef __IOS__
|
||||||
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
save_image_library(name);
|
||||||
NSURL* url = [NSURL fileURLWithPath : [NSString stringWithUTF8String : name]];
|
|
||||||
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL : url];
|
|
||||||
changeRequest.creationDate = [NSDate date];
|
|
||||||
} completionHandler: ^ (BOOL success, NSError *error) {
|
|
||||||
if (success) {
|
|
||||||
NSLog(@"successfully saved");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
NSLog(@"error saving to photos : %@", error);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
[files addObject:[NSString stringWithUTF8String : name]];
|
[files addObject:[NSString stringWithUTF8String : name]];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#ifdef __OBJC__
|
#ifdef __OBJC__
|
||||||
|
#import <Photos/Photos.h>
|
||||||
@implementation PathWithModDate
|
@implementation PathWithModDate
|
||||||
@end
|
@end
|
||||||
@implementation ObjcUtils
|
@implementation ObjcUtils
|
||||||
@@ -122,3 +123,194 @@ void install_global_handlers()
|
|||||||
std::set_terminate(TerminateHandler);
|
std::set_terminate(TerminateHandler);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void delete_all_files_in_path(const std::string& source_path)
|
||||||
|
{
|
||||||
|
NSString *path = [NSString stringWithUTF8String:source_path.c_str()];
|
||||||
|
NSDirectoryEnumerator* en = [[NSFileManager defaultManager] enumeratorAtPath:path];
|
||||||
|
LOG("delete all files from %s", source_path.c_str());
|
||||||
|
while (NSString* file = [en nextObject])
|
||||||
|
{
|
||||||
|
NSString* file_path = [path stringByAppendingPathComponent:file];
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:file_path error:nil];
|
||||||
|
LOG("delete: %s", [file_path UTF8String]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stillImageDataReleaseCallback(void *releaseRefCon, const void *baseAddress)
|
||||||
|
{
|
||||||
|
free((void *)baseAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_mp4(const std::string& rec_path, int width, int height, int tot, void(^progress_callback)(float))
|
||||||
|
{
|
||||||
|
int progress = 0;
|
||||||
|
NSString* mov_path = [NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()];
|
||||||
|
if ([[NSFileManager defaultManager] fileExistsAtPath:mov_path])
|
||||||
|
{
|
||||||
|
NSLog(@"remove existing mp4");
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:mov_path error:nil];
|
||||||
|
}
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()]];
|
||||||
|
AVAssetWriter* writer = [AVAssetWriter assetWriterWithURL:url fileType:AVFileTypeMPEG4 error:nil];
|
||||||
|
writer.shouldOptimizeForNetworkUse = NO;
|
||||||
|
NSDictionary *videoCompressionSettings = @{
|
||||||
|
AVVideoCodecKey : AVVideoCodecH264,
|
||||||
|
AVVideoWidthKey : @(width),
|
||||||
|
AVVideoHeightKey : @(height),
|
||||||
|
AVVideoCompressionPropertiesKey : @{ AVVideoAverageBitRateKey : @(8<<20) }
|
||||||
|
};
|
||||||
|
if (![writer canApplyOutputSettings:videoCompressionSettings forMediaType:AVMediaTypeVideo])
|
||||||
|
{
|
||||||
|
NSLog(@"Couldn't add asset writer video input.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AVAssetWriterInput* input = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo
|
||||||
|
outputSettings:videoCompressionSettings
|
||||||
|
sourceFormatHint:nil];
|
||||||
|
input.expectsMediaDataInRealTime = YES;
|
||||||
|
|
||||||
|
NSDictionary *adaptorDict = @{
|
||||||
|
(id)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32BGRA),
|
||||||
|
(id)kCVPixelBufferWidthKey : @(width),
|
||||||
|
(id)kCVPixelBufferHeightKey : @(height)
|
||||||
|
};
|
||||||
|
|
||||||
|
AVAssetWriterInputPixelBufferAdaptor* _pixelBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc]
|
||||||
|
initWithAssetWriterInput:input
|
||||||
|
sourcePixelBufferAttributes:adaptorDict];
|
||||||
|
|
||||||
|
|
||||||
|
// Add asset writer input to asset writer
|
||||||
|
if (![writer canAddInput:input]) {
|
||||||
|
NSLog(@"Couldn't add input to writer.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[writer addInput:input];
|
||||||
|
|
||||||
|
CMTime t;
|
||||||
|
t.timescale = 30;
|
||||||
|
t.flags = kCMTimeFlags_Valid;
|
||||||
|
t.epoch = 0;
|
||||||
|
t.value = 0;
|
||||||
|
//[writer startSessionAtSourceTime:t];
|
||||||
|
|
||||||
|
CVPixelBufferRef buff = NULL;
|
||||||
|
uint8_t* data = (uint8_t*)calloc(1, width * height * 4);
|
||||||
|
CVPixelBufferCreateWithBytes(kCFAllocatorDefault, width, height, kCVPixelFormatType_32RGBA, data,
|
||||||
|
width * 4, stillImageDataReleaseCallback, nil, nil, &buff);
|
||||||
|
OSStatus err = CVPixelBufferPoolCreatePixelBuffer(nil, _pixelBufferAdaptor.pixelBufferPool, &buff);
|
||||||
|
|
||||||
|
|
||||||
|
if (writer.status == AVAssetWriterStatusUnknown)
|
||||||
|
{
|
||||||
|
// If the asset writer status is unknown, implies writing hasn't started yet, hence start writing with start time as the buffer's presentation timestamp
|
||||||
|
if ([writer startWriting])
|
||||||
|
{
|
||||||
|
[writer startSessionAtSourceTime:t];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writer.status == AVAssetWriterStatusWriting)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tot; i++)
|
||||||
|
{
|
||||||
|
// If the asset writer status is writing, append sample buffer to its corresponding asset writer input
|
||||||
|
if (input.readyForMoreMediaData)
|
||||||
|
{
|
||||||
|
char path[256];
|
||||||
|
snprintf(path, sizeof(path), "%s/%04d.jpg", rec_path.c_str(), i);
|
||||||
|
NSString* img_path = [NSString stringWithUTF8String:path];
|
||||||
|
NSLog(@"frame: %@", img_path);
|
||||||
|
#if __OSX__
|
||||||
|
NSImage *image = [[NSImage alloc] initWithContentsOfFile:img_path];
|
||||||
|
if (!image)
|
||||||
|
break;
|
||||||
|
NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);
|
||||||
|
CGImageRef cgImage = [image CGImageForProposedRect:&imageRect context:NULL hints:nil];
|
||||||
|
#elif __IOS__
|
||||||
|
UIImage* image = [UIImage imageNamed:img_path];
|
||||||
|
if (!image)
|
||||||
|
break;
|
||||||
|
CGImageRef cgImage = image.CGImage;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
|
[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
|
||||||
|
[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
|
||||||
|
CGSize sz = image.size;
|
||||||
|
CVPixelBufferRef pxbuffer = NULL;
|
||||||
|
{
|
||||||
|
CGImageRef image = cgImage;
|
||||||
|
CGSize size = sz;
|
||||||
|
CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
|
||||||
|
// CVReturn status = CVPixelBufferPoolCreatePixelBuffer(NULL, adaptor.pixelBufferPool, &pxbuffer);
|
||||||
|
|
||||||
|
//NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
|
||||||
|
|
||||||
|
CVPixelBufferLockBaseAddress(pxbuffer, 0);
|
||||||
|
void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
|
||||||
|
//NSParameterAssert(pxdata != NULL);
|
||||||
|
|
||||||
|
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
|
CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
|
||||||
|
//NSParameterAssert(context);
|
||||||
|
|
||||||
|
CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
|
||||||
|
|
||||||
|
CGColorSpaceRelease(rgbColorSpace);
|
||||||
|
CGContextRelease(context);
|
||||||
|
|
||||||
|
CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.value = i;
|
||||||
|
if (![_pixelBufferAdaptor appendPixelBuffer:pxbuffer withPresentationTime:t])
|
||||||
|
{
|
||||||
|
NSLog(@"error %@", [writer.error localizedFailureReason]);
|
||||||
|
}
|
||||||
|
CFRelease(pxbuffer);
|
||||||
|
|
||||||
|
progress++;
|
||||||
|
progress_callback((float)progress / tot * 100.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[input markAsFinished];
|
||||||
|
[writer finishWritingWithCompletionHandler:^{
|
||||||
|
NSString* path = [NSString stringWithFormat:@"%s/out.mp4", rec_path.c_str()];
|
||||||
|
NSLog(@"saved video %@", path);
|
||||||
|
#if __IOS__
|
||||||
|
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path))
|
||||||
|
{
|
||||||
|
NSLog(@"saving to camera roll");
|
||||||
|
UISaveVideoAtPathToSavedPhotosAlbum(path, nil, nil, nil);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writer.status == AVAssetWriterStatusFailed)
|
||||||
|
{
|
||||||
|
NSLog(@"failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_image_library(const std::string& path)
|
||||||
|
{
|
||||||
|
#if __IOS__
|
||||||
|
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
|
||||||
|
NSURL* url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:path.c_str()]];
|
||||||
|
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImageAtFileURL:url];
|
||||||
|
changeRequest.creationDate = [NSDate date];
|
||||||
|
} completionHandler:^(BOOL success, NSError *error) {
|
||||||
|
if (success) {
|
||||||
|
NSLog(@"successfully saved");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSLog(@"error saving to photos: %@", error);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,3 +11,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void install_global_handlers();
|
void install_global_handlers();
|
||||||
|
void delete_all_files_in_path(const std::string& source_path);
|
||||||
|
void export_mp4(const std::string& rec_path, int width, int height, int tot, void(^progress_callback)(float));
|
||||||
|
void save_image_library(const std::string& path);
|
||||||
|
|||||||
Reference in New Issue
Block a user