如何在iOS中获取音频文件的持续时间?

Nam*_*tha 44 audio duration file nsdictionary ios

NSDictionary* fileAttributes = 
    [[NSFileManager defaultManager] attributesOfItemAtPath:filename 
                                                     error:nil]
Run Code Online (Sandbox Code Playgroud)

从文件属性键,您可以获得日期,大小等.但是如何获得持续时间?

Jam*_*ord 127

NSFileManager类引用"文件属性键"中,您可以看到没有要使用的键将返回歌曲的持续时间.NSFileManager实例获取文件的所有信息都与操作系统中实际文件本身的属性有关,例如文件大小.该的NSFileManager实际上并不解释文件.

为了获得文件的持续时间,您需要使用知道如何解释文件的类.该AVFoundation框架提供你所需要的确切类,AVAsset.您可以使用具体的子类AVURLAsset实例化此抽象类的实例,然后为其提供一个NSURL,指向您希望获得持续时间的音频文件.然后,您可以通过查询其属性从AVAsset实例获取持续时间duration.

例如:

AVURLAsset* audioAsset = [AVURLAsset URLAssetWithURL:audioFileURL options:nil];
CMTime audioDuration = audioAsset.duration;
float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
Run Code Online (Sandbox Code Playgroud)

请注意,AVFoundation被设计为高度异步的框架,以提高性能和整体用户体验.即使执行简单的任务(例如查询媒体文件的持续时间)也可能需要很长时间,并且可能导致应用程序挂起.您应该使用AVAsynchronousKeyValueLoading协议异步加载歌曲的持续时间,然后在完成处理程序块中更新UI.您应该查看"块编程指南"以及标题为"发现AV基础"的WWDC2010视频,该视频可从https://developer.apple.com/videos/wwdc/2010免费获得.

  • 我总是得到0持续时间 (8认同)
  • 除了AVFoundation之外,还要确保添加和导入CoreMedia框架.谢谢你这种有效的方法,詹姆斯. (2认同)
  • 该方法阻塞UIThread (2认同)

小智 14

为了完整性 - 还有另一种方法来获取mp3文件的持续时间:

NSURL * pathToMp3File = ...
NSError *error = nil;
AVAudioPlayer* avAudioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:pathToMp3File error:&error];

double duration = avAudioPlayer.duration; 
avAudioPlayer = nil;
Run Code Online (Sandbox Code Playgroud)

我用这个没有明显的延迟.

  • 这种方法不准确,很多时候会以秒为单位缩短持续时间 (2认同)

Ash*_*ldr 9

您可以使用以下方法在Swift中实现相同:

let audioAsset = AVURLAsset.init(url: audioFileURL, options: nil)
let duration = audioAsset.duration
let durationInSeconds = CMTimeGetSeconds(duration)
Run Code Online (Sandbox Code Playgroud)

  • 此方法会导致延迟 (3认同)

nCr*_*r78 6

对于仍在寻找这个的人。基于答案,Swift 4的代码(包括异步加载来自Apple文档的值):

let audioAsset = AVURLAsset.init(url: yourURL, options: nil)

audioAsset.loadValuesAsynchronously(forKeys: ["duration"]) {
    var error: NSError? = nil
    let status = audioAsset.statusOfValue(forKey: "duration", error: &error)
    switch status {
    case .loaded: // Sucessfully loaded. Continue processing.
        let duration = audioAsset.duration
        let durationInSeconds = CMTimeGetSeconds(duration)
        print(Int(durationInSeconds))
        break              
    case .failed: break // Handle error
    case .cancelled: break // Terminate processing
    default: break // Handle all other cases
    }
}
Run Code Online (Sandbox Code Playgroud)


Bar*_*mre 6

Swift 5.0 + iOS 13:这是对我有用的唯一方法(Swift 中的@John Goodstadt 解决方案)。目前我不确定为什么,但是使用以下代码录制的音频文件(在我的情况下是语音备忘录)和接收到的音频文件之间平均存在 0.2 秒的差异。

    do {
        let audioPlayer = try AVAudioPlayer(contentsOf: fileURL)
        return CGFloat(audioPlayer.duration)
    } catch {
        assertionFailure("Failed crating audio player: \(error).")
        return nil
    }
Run Code Online (Sandbox Code Playgroud)

  • 这会导致像 android 一样阻塞主线程 (2认同)