UIImagePickerController
录制视频时,我使用以下代码可以很好地工作,但是如果从相机胶卷中选择视频,则会出现以下错误,我不知道原因所在:
导出失败:操作停止:错误 Domain=AVFoundationErrorDomain Code=-11841 "Operation Stopped" UserInfo=0x1815ca50 {NSLocalizedDescription=Operation Stopped, NSLocalizedFailureReason=The video could not be composed.}
我已经尝试先将视频保存到另一个文件中,但没有任何区别。
以下是我用于转换视频的代码:
- (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:(NSURL*)inputURL handler:(void (^)(NSURL *outURL))handler
{
if ([[inputURL pathExtension] isEqualToString:@"MOV"])
{
NSURL *outputURL = [inputURL URLByDeletingPathExtension];
outputURL = [outputURL URLByAppendingPathExtension:@"mp4"];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil];
AVAssetTrack *sourceVideoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *sourceAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceVideoTrack
atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform];
AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration)
ofTrack:sourceAudioTrack
atTime:kCMTimeZero error:nil];
AVMutableVideoComposition *videoComposition = [self getVideoComposition:avAsset];
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality])
{
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetMediumQuality];
exportSession.outputURL = outputURL;
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.videoComposition = videoComposition;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status])
{
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@ : %@", [[exportSession error] localizedDescription], [exportSession error]);
handler(nil);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
handler(nil);
break;
default:
handler(outputURL);
break;
}
}];
}
} else {
handler(inputURL);
}
}
- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset
{
AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
CGSize videoSize = videoTrack.naturalSize;
BOOL isPortrait_ = [self isVideoPortrait:asset];
if(isPortrait_) {
// NSLog(@"video is portrait ");
videoSize = CGSizeMake(videoSize.height, videoSize.width);
}
composition.naturalSize = videoSize;
videoComposition.renderSize = videoSize;
videoComposition.frameDuration = CMTimeMakeWithSeconds( 1 / videoTrack.nominalFrameRate, 600);
AVMutableCompositionTrack *compositionVideoTrack;
compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionLayerInstruction *layerInst;
layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero];
AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
inst.layerInstructions = [NSArray arrayWithObject:layerInst];
videoComposition.instructions = [NSArray arrayWithObject:inst];
return videoComposition;
}
composable
,exportable
和hasProtectedContent
都是您所说的。您的第一个建议没有返回任何错误。我尝试将音频轨道更改为使用 44,100。 如果我注释掉exportSession.videoComposition = videoComposition;
,它可以正常工作,但视频不会旋转。因此问题必须出在那里。谢谢。 - Darren-(AVMutableVideoComposition *)getVideoComposition
中创建了一个AVMutableComposition
,并从中创建了AVMutableCompositionTrack
。然而,在- (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:handler:
中,你有一个 不同的AVMutableComposition
,你正在将其传递给AVExportSession
。尝试将此组合传递给 getVideoComposition 以从中创建 AVMutableCompositionTracks,这样就只有一个组合了。 - jlwAVMutableVideoComposition
和AVMutableVideoCompositionLayerInstruction
向上移动到主要的转换方法中,这样就只有一个AVMutableComposition
,但结果仍然相同。从照片库选择视频时,在传递之前会对其进行压缩,不确定是否会有影响。 - DarrenAVMutableVideoCompositionTracks
,一个用于音频,一个用于视频。你应该基于sourceVideoTrack
创建AVMutableVideoCompositionLayerInstruction
,并尝试仅在指令上设置变换。当你在项目中使用AVCompositionDebugViewer
类时,它是否显示你期望的内容? - jlwAVAssetExportSession
提供了有限的预设,影响质量和文件大小。你可能想要研究一下AVAssetWriter
(以及AVAssetWriterInput
/AVAssetReaderTrackOutput
),在那里你可以指定平均比特率等设置。你可以使用的设置列在https://developer.apple.com/library/iOS/documentation/AVFoundation/Reference/AVFoundation_Constants/Reference/reference.html 的视频设置中。 - jlw