如何使用AVAssetExportSession导出AVPlayer音频mp3文件?

5

我现在正在尝试使用AVPlayer(使用URL)播放的MP3文件进行导出,以便不必再次下载。

这是我的示例代码:

我已经尝试了每种outputFileType...

    self.exporter = [[AVAssetExportSession alloc] initWithAsset:self.asset presetName:AVAssetExportPresetPassthrough];
        }

        NSError *error;

        NSLog(@"export.supportedFileTypes : %@",self.exporter.supportedFileTypes);
       //        "com.apple.quicktime-movie",
//        "com.apple.m4a-audio",
//        "public.mpeg-4",
//        "com.apple.m4v-video",
//        "public.3gpp",
//        "org.3gpp.adaptive-multi-rate-audio",
//        "com.microsoft.waveform-audio",
//        "public.aiff-audio",
//        "public.aifc-audio",
//        "com.apple.coreaudio-format"

        self.exporter.outputFileType = @"public.aiff-audio";
        self.exporter.shouldOptimizeForNetworkUse = YES;

        NSURL *a = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:&error];

        NSURL *url = [a URLByAppendingPathComponent:@"filename.mp3"];

        NSString *filePath = [url absoluteString];

        self.exporter.outputURL = url;

        if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]){
            [self.exporter exportAsynchronouslyWithCompletionHandler:^{

                if (self.exporter.status == AVAssetExportSessionStatusCompleted)
                {

                    if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]){
                        NSLog(@"File doesn't exist at path");
                    }else {
                        NSLog@"File saved!");
}                    
                }
                else if(self.exporter.status == AVAssetExportSessionStatusFailed){
                    NSLog(@"Failed");
                }else if(self.exporter.status == AVAssetExportSessionStatusUnknown){
                    NSLog(@"Unknown");
                }else if(self.exporter.status == AVAssetExportSessionStatusCancelled){
                    NSLog(@"Cancelled");
                }else if(self.exporter.status == AVAssetExportSessionStatusWaiting){
                    NSLog(@"Waiting");
                }else if(self.exporter.status == AVAssetExportSessionStatusExporting){
                    NSLog(@"Exporting");
                }

                NSLog(@"Exporter error! : %@",self.exporter.error);

              }];

        }}else{
            NSLog(@"File already exists at path");
        }

如果无法实现这一点,是否有任何解决方法?

另外,我可以更改音频文件的格式。与AVAudioPlayer一起使用的理想类型是什么?


是的,即使是苹果自己的AVFoundationExporter示例项目似乎也无法使用mp3文件和AVAssetExportPresetPassthrough预设。 - Dalmazio
看这里的答案,可能会对你有所帮助: https://dev59.com/iVnUa4cB1Zd3GeqPffMl#47327516 - Usman Nisar
3个回答

10

看起来,AVAssetExportSession只支持使用com.apple.quicktime-movie(.mov)和com.apple.coreaudio-format(.caf)格式的文件类型进行mp3转码,并使用AVAssetExportPresetPassthrough预设。在输出文件时,您还必须确保使用这些文件扩展名,否则它将无法保存。

以下是加粗显示的mp3输入文件所支持的输出文件类型和扩展名(在OS X 10.11.6上测试通过):

  • com.apple.quicktime-movie (.mov)
  • com.apple.m4a-audio (.m4a)
  • public.mpeg-4 (.mp4)
  • com.apple.m4v-video (.m4v)
  • org.3gpp.adaptive-multi-rate-audio (.amr)
  • com.microsoft.waveform-audio (.wav)
  • public.aiff-audio (.aiff)
  • public.aifc-audio (.aifc)
  • com.apple.coreaudio-format (.caf)

如果您不介意对音频数据进行适当的转码以使用其他格式,则不必使用AVAssetExportPresetPassthrough预设。还有AVAssetExportPresetLowQualityAVAssetExportPresetMediumQualityAVAssetExportPresetHighestQuality可用。在下面的示例代码中,输出URL使用扩展名.m4a,生成的转码可以在iTunes和其他媒体播放器中播放:

AVAsset * asset = [AVAsset assetWithURL:inputURL];
AVAssetExportSession * exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:AVAssetExportPresetHighestQuality];
exportSession.outputFileType = AVFileTypeMPEG4;
exportSession.outputURL = outputURL;
exportSession.metadata = asset.metadata;       
[exportSession exportAsynchronouslyWithCompletionHandler:^{

    if (exportSession.status == AVAssetExportSessionStatusCompleted)
    {
            NSLog(@"AV export succeeded.");
    }
    else if (exportSession.status == AVAssetExportSessionStatusCancelled)
    {
        NSLog(@"AV export cancelled.");
    }
    else
    {
        NSLog(@"AV export failed with error: %@ (%ld)", exportSession.error.localizedDescription, (long)exportSession.error.code);
    }
}];

尝试了你的方法。我得到了一个可以在QuickTime中播放但无法在iTunes和其他一些播放器中播放的mp3文件。你知道怎么解决吗? - iOS Dev
看起来你不能使用AVAssetExportPresetPassthrough实现它。我正在将其转码为.m4a但是我正在使用AVAssetExportPresetLowQuality预设,它实际上将音频数据转换为不同的格式,并且它工作得很好。你可以尝试其他一些预设,包括AVAssetExportPresetMediumQualityAVAssetExportPresetHighestQuality。让我更新我的答案并提供额外的信息。 - Dalmazio
@Dalmazio,根据您的经验,将视频转换为mp3的正确方法是什么? - Roi Mulia

0

我尝试从iPod库中导出mp3格式的音频文件。以下是我的解决方案。

extension DirectoryListViewController: MPMediaPickerControllerDelegate {
public func mediaPicker(_ mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
    guard let mediaItem = mediaItemCollection.items.first else { ImportExternalFileService.shared.alertImportError(); return  }
    guard let url = mediaItem.assetURL else { ImportExternalFileService.shared.alertImportError(); return }
    guard let songTitle = mediaItem.title else { ImportExternalFileService.shared.alertImportError(); return }
    guard let exportSession = AVAssetExportSession(asset: AVURLAsset(url: url), presetName: AVAssetExportPresetAppleM4A) else {
        ImportExternalFileService.shared.alertImportError(); return
    }
    exportSession.outputFileType = .m4a
    exportSession.metadata = AVURLAsset(url: url).metadata
    exportSession.shouldOptimizeForNetworkUse = true
    guard let fileExtension = UTTypeCopyPreferredTagWithClass(exportSession.outputFileType!.rawValue as CFString, kUTTagClassFilenameExtension) else {
        ImportExternalFileService.shared.alertImportError(); return
    }
    let documentURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    let outputURL = documentURL.appendingPathComponent("\(songTitle).\(fileExtension.takeUnretainedValue())")
    /* Dont't forget to remove the existing url, or exportSession will throw error: can't save file */
    do {
        try FileManager.default.removeItem(at: outputURL)
    } catch let error as NSError {
        print(error.debugDescription)
    }
    exportSession.outputURL = outputURL
    exportSession.exportAsynchronously(completionHandler: {
        if exportSession.status == .completed {
            DispatchQueue.main.async {
                ImportExternalFileService.shared.importRecordFile(url: exportSession.outputURL!)
            }
        } else {
            print("AV export failed with error:- ", exportSession.error!.localizedDescription)
        }
    })
}

public func mediaPickerDidCancel(_ mediaPicker: MPMediaPickerController) {
    dismiss(animated: true, completion: nil)
}

}


0

你不能这样做,但你可以导出m4a格式。

AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:audioAsset presetName:AVAssetExportPresetAppleM4A];
exportSession.outputURL = [NSURL fileURLWithPath:exportPath];
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{

}];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接