Dir*_*irk 13 objective-c avfoundation ios avcapturesession avcapturemoviefileoutput
我一直在为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;
Run Code Online (Sandbox Code Playgroud)
}
当可用空间(减去缓冲区)减少到零时,抛出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];
});
}
Run Code Online (Sandbox Code Playgroud)
当两个错误都被抛出时,会出现"写入相册".我完全被这个难过了.任何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
}
Run Code Online (Sandbox Code Playgroud)
问题 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;
}];
Run Code Online (Sandbox Code Playgroud)
如果修复这些问题无法解决问题,请提供缺少的代码以使示例编译。
| 归档时间: |
|
| 查看次数: |
958 次 |
| 最近记录: |