Próbuję konwertować wideo .mov na .mp4 i jednocześnie korygować orientację. Kod używam poniżej działa świetnie podczas nagrywania wideo za pomocą UIImagePickerController
jednak jeśli film jest wybrany z rolki aparatu otrzymuję ten błąd i nie widzę dlaczego:Błąd obracania AVAssetExportSession, gdy wideo pochodzi z rolki kamery.
Export failed: Operation Zatrzymany: Błąd domain = Kod AVFoundationErrorDomain = -11841 "Operacja zatrzymana" UserInfo = 0x1815ca50 {NSLocalizedDescription = Operacja zatrzymana, NSLocalizedFailureReason = film nie mógł być złożony.}
próbowałem najpierw zapisywanie wideo do innego pliku, ale to nie miało znaczenia.
Oto kod używam do konwersji wideo:
- (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;
}
dziękuję za bardzo szczegółową odpowiedź. Nadal nie mogę go uruchomić :( 'composable',' exportable' & 'hasProtectedContent' are4 wszystko, co powinieneś.Jednak nie ma błędów zwrócony z pierwszej sugestii.Próbowałem zmienić ścieżkę audio, aby użyć 44 100. Jeśli skomentuję 'exportSession.videoComposition = videoComposition;' działa dobrze, ale wideo nie jest obrócone, więc problem musi gdzieś tam być.Dziękuję – Darren
Zauważam, że tworzysz 'AVMutableComposition' w' - (AVMutableVideoComposition *) getVideoComposition', i stwórz 'AVMutableCompositionTrack's z tego.} Jednakże w' - (void) convertVideoToLowQuailtyAndFixRotationWithInputURL: handler: ' , masz _różny_" AVMutableComposition ", który przechodzisz do' AVExportSession'. Spróbuj przekazać tę kompozycję do getVideoComposition aby utworzyć ścieżki AVMutableComposition Track z niego, więc jest tylko jeden. – jlw
Po prostu próbowałem przesuwać 'AVMutableVideoComposition' za pomocą' AVMutableVideoCompositionLayerInstruction' do głównej metody konwersji, tak aby zawierała tylko 1 'AVMutableComposition', ale wciąż takie same wyniki. Wybierając wideo z rolki aparatu, kompresuje je przed przekazaniem, nie będąc pewnym, czy to właśnie robi różnicę. – Darren