合并音频文件时 AVAssetExportSessionStatusFailed IOS 9

AVAssetExportSessionStatusFailed While Merging Audio files in IOS 9

我已经使用了这段代码,它在 IOS 9 的早期版本上工作得很好。但是在 IOS 9 版本上它总是会出现 AVAssetExportSessionStatusFailed

AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/firstPart.caf",docsDir]] options:nil];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/New-Recording.caf",docsDir]] options:nil];

AVMutableComposition *composition = [[AVMutableComposition alloc] init];
[composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

AVAssetTrack *assetTrack1;
AVAssetTrack *assetTrack2;

if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
    assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}

CMTime insertionPoint = kCMTimeZero;
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:nil];
insertionPoint = CMTimeAdd(insertionPoint, avAsset1.duration);
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:assetTrack2 atTime:insertionPoint error:nil];

AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/mergedFilePart1.caf",documentsDirectory]];
exportSession.outputFileType = AVFileTypeAppleM4A;

[exportSession exportAsynchronouslyWithCompletionHandler:^{
    if (AVAssetExportSessionStatusCompleted == exportSession.status) {

        NSLog(@"AVAssetExportSessionStatusCompleted");

        [self mergeAudioPart2];

    } else if (AVAssetExportSessionStatusFailed == exportSession.status) {
        NSLog(@"AVAssetExportSessionStatusFailed");
    } else {
        NSLog(@"Export Session Status: %ld", (long)exportSession.status);
    }
}];

我在整个互联网上进行了搜索,但没有找到任何解决方案,我们将不胜感激。

您的代码应该 可以工作,但如果没有看到您的输入文件,就很难判断。不过还是可以改进的。

出于某种原因,您有一个未使用的可变轨道。您可以删除它:

AVMutableComposition *composition = [[AVMutableComposition alloc] init];
// This track is unused. Delete it!
// [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

导出失败时 (AVAssetExportSessionStatusFailed == exportSession.status) 查看 exportSession.error 了解更多信息。 AVFoundation 错误消息通常有很多不足之处,但你可能很幸运。

您正在导出 m4a 文件,但文件后缀为 .caf。将其更改为 .m4aAVAssetExportSession 似乎不支持导出到 AVFileTypeCoreAudioFormat)。 确保在导出之前始终删除输出 URL,你忘记这样做了:

NSURL *ouputURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/mergedFilePart1.m4a",documentsDirectory]];
[[NSFileManager defaultManager] removeItemAtURL:ouputURL error:nil];

AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = ouputURL;
exportSession.outputFileType = AVFileTypeAppleM4A;

insertTimeRange:ofTrack:error: returns 一个成功标志和一个错误!咨询他们!他们可能指出您的代码有问题!

NSError *error;
if (![track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:&error]) {
    NSLog(@"ERROR 1: %@", error);
}

这个条件很奇怪。您检查一项资产中是否存在音轨,然后也使用另一项资产:

if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
    assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}

问题出在这里: // [组合 addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];这条线增加了额外的轨道。现在这段代码在 IOS 9 上也能完美运行。

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *path1 = [NSString stringWithFormat:@"%@/firstPart.caf",documentsDirectory];
NSString *path2 = [NSString stringWithFormat:@"%@/New-Recording.caf",documentsDirectory];

AVAsset *avAsset1 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path1] options:nil];
AVAsset *avAsset2 = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:path2] options:nil];

AVMutableComposition *composition = [[AVMutableComposition alloc] init];
//    [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack *track = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

AVAssetTrack *assetTrack1;
AVAssetTrack *assetTrack2;

if ([avAsset1 tracksWithMediaType:AVMediaTypeAudio].count > 0) {
    assetTrack1 = [[avAsset1 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
    assetTrack2 = [[avAsset2 tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
}

NSError *error;

CMTime insertionPoint = kCMTimeZero;

[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset1.duration) ofTrack:assetTrack1 atTime:insertionPoint error:nil];
insertionPoint = CMTimeAdd(insertionPoint, avAsset1.duration);
[track insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset2.duration) ofTrack:assetTrack2 atTime:insertionPoint error:nil];

NSURL *outPutUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/mergedFilePart1.caf",documentsDirectory]];


AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPresetAppleM4A];

exportSession.outputURL = outPutUrl;

exportSession.outputFileType = AVFileTypeAppleM4A;

[exportSession exportAsynchronouslyWithCompletionHandler:^{
    if (AVAssetExportSessionStatusCompleted == exportSession.status) {

        NSLog(@"AVAssetExportSessionStatusCompleted");
        [self mergeAudioPart2];

    } else if (AVAssetExportSessionStatusFailed == exportSession.status) {

        NSLog(@"%ld",(long)exportSession.status);
        NSLog(@"AVAssetExportSessionStatusFailed");
    } else {
        NSLog(@"Export Session Status: %ld", (long)exportSession.status);
    }
}];