gpt4 book ai didi

ios - 使用 maxRecordedFileSize 限制 AVCaptureSession 记录时间

转载 作者:技术小花猫 更新时间:2023-10-29 10:28:08 29 4
gpt4 key购买 nike

我一直在为 iOS 8 编写相机应用程序,它使用 AVFoundation 来设置和处理记录和保存(而不是 ImagePickerController)。我试图保存使用 AVCaptureMovieFileOutput 类的 maxRecordedFileSize 属性,以允许用户填满手机上的所有可用空间(减去 250MB 的缓冲区留给苹果的东西)。

- (unsigned long long) availableFreespaceInMb {
unsigned long long freeSpace;
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error];

if (dictionary) {
NSNumber *fileSystemFreeSizeInBytes = [dictionary objectForKey: NSFileSystemFreeSize];
freeSpace = [fileSystemFreeSizeInBytes unsignedLongLongValue];

} else {
NSLog(@"Error getting free space");
//Handle error
}

//convert to MB
freeSpace = (freeSpace/1024ll)/1024ll;
freeSpace -= _recordSpaceBufferInMb; // 250 MB
NSLog(@"Remaining space in MB: %llu", freeSpace);
NSLog(@" Diff Since Last: %llu", (_prevRemSpaceMb - freeSpace));

_prevRemSpaceMb = freeSpace;
return freeSpace;

AVErrorMaximumFileSizeReached 当可用空间(减去缓冲区)减少到零时抛出,并且没有抛出保存错误,但视频没有出现在相机胶卷中,也没有被保存。当我设置 maxRecordedDuration 字段时,会抛出 AVErrorMaximumDurationReached 并且视频会保存。我根据最大大小计算最大时间,但由于帧压缩,我总是有足够的空间。

- (void) toggleMovieRecording
{
double factor = 1.0;
if (_currentFramerate == _slowFPS) {
factor = _slowMotionFactor;
}

double availableRecordTimeInSeconds = [self remainingRecordTimeInSeconds] / factor;
unsigned long long remainingSpace = [self availableFreespaceInMb] * 1024 * 1024;

if (![[self movieFileOutput] isRecording]) {
if (availableSpaceInMb < 50) {
NSLog(@"TMR:Not enough space, can't record");
[AVViewController currentVideoOrientation];
[_previewView memoryAlert];
return;
}
}

if (![self enableRecording]) {
return;
}

[[self recordButton] setEnabled:NO];

dispatch_async([self sessionQueue], ^{
if (![[self movieFileOutput] isRecording])
{
if ([[UIDevice currentDevice] isMultitaskingSupported])
{
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]];
}

// Update the orientation on the movie file output video connection before starting recording.
[[[self movieFileOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation: [AVViewController currentVideoOrientation]];//[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];

// Start recording to a temporary file.
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[@"movie" stringByAppendingPathExtension:@"mov"]];

// Is there already a file like this?
NSFileManager *fileManager = [NSFileManager defaultManager];

if ([fileManager fileExistsAtPath:outputFilePath]) {
NSLog(@"filexists");
NSError *err;
if ([fileManager removeItemAtPath:outputFilePath error:&err] == NO) {
NSLog(@"Error, file exists at path");
}
}

[_previewView startRecording];

// Set the movie file output to stop recording a bit before the phone is full
[_movieFileOutput setMaxRecordedFileSize:remainingSpace]; // Less than the total remaining space
// [_movieFileOutput setMaxRecordedDuration:CMTimeMake(availableRecordTimeInSeconds, 1.0)];

[_movieFileOutput startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
}
else
{
[_previewView stopRecording];
[[self movieFileOutput] stopRecording];
}
});
}

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error

NSLog(@"AVViewController: didFinishRecordingToOutputFile");

if (error) {
NSLog(@"%@", error);
NSLog(@"Caught Error");
if ([error code] == AVErrorDiskFull) {
NSLog(@"Caught disk full error");
} else if ([error code] == AVErrorMaximumFileSizeReached) {
NSLog(@"Caught max file size error");
} else if ([error code] == AVErrorMaximumDurationReached) {
NSLog(@"Caught max duration error");
} else {
NSLog(@"Caught other error");
}

[self remainingRecordTimeInSeconds];

dispatch_async(dispatch_get_main_queue(), ^{
[_previewView stopRecording];
[_previewView memoryAlert];
});
}

// Note the backgroundRecordingID for use in the ALAssetsLibrary completion handler to end the background task associated with this recording. This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's -isRecording is back to NO — which happens sometime after this method returns.
UIBackgroundTaskIdentifier backgroundRecordingID = [self backgroundRecordingID];
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];

[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
if (error) {
NSLog(@"%@", error);
NSLog(@"Error during write");
} else {
NSLog(@"Writing to photos album");
}

[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];

if (backgroundRecordingID != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:backgroundRecordingID];
}];

if (error) {
[_session stopRunning];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC), _sessionQueue, ^{
[_session startRunning];
});
}

当两个错误都被抛出时,会出现“正在写入相册”。我完全被这个难住了。任何 iOS 见解?

最佳答案

您提供的代码示例很难测试,因为缺少属性和方法。虽然我无法编译您的代码,但肯定有一些危险信号可能会导致问题。在内部发现了以下问题: captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:

问题 1:该方法正在处理传入的错误,但随后继续执行该方法。相反,它应该是:

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error { 
if (error) {
// handle error then bail
return;
}

// continue on
}

问题 2:您正在实例化的 ALAssetsLibrary 对象未存储到属性中,因此一旦 captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error: 完成该对象将被释放(可能永远不会触发您的完成堵塞)。相反,它应该是:

// hold onto the assets library beyond this scope
self.assetsLibrary = [[ALAssetsLibrary alloc] init];

// get weak reference to self for later removal of the assets library
__weak typeof(self) weakSelf = self;
[self.assetsLibrary writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock:^(NSURL *assetURL, NSError *error) {
// handle error
// handle cleanup

// cleanup new property
weakSelf.assetsLibrary = nil;
}];

如果解决这些问题不能解决问题,请提供缺少的代码以使您的示例编译。

关于ios - 使用 maxRecordedFileSize 限制 AVCaptureSession 记录时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30857507/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com