在Android中获取音频文件持续时间的最佳方法是什么?

14
我正在使用SoundPool播放我的应用程序中的音频剪辑。一切都很好,但我需要知道剪辑播放何时结束。
目前,我通过获取每个片段的持续时间来跟踪它在我的应用程序中。使用MediaPlayer实例可以完成这项工作。这很有效,但似乎浪费了加载每个文件两次的时间。我可以通过已知文件长度(可从AssetFileDescriptor中获得)粗略地计算出持续时间,但我仍然需要知道采样率和通道数。
我看到了解决这个问题的两个潜在方法:
  1. 找出何时播放片段已经完成(似乎无法使用SoundClip实现)。
  2. 拥有一个类,它可以只加载音频文件的头,并提供采样率/通道数(最好还有采样计数以获得精确的持续时间)。
任何建议吗?
谢谢, Max
我目前正在使用的代码(效果很好,但对于这个目的而言过于重量级):
String[] fileNames = ...
MediaPlayer mp = new MediaPlayer();
for (String fileName : fileNames) {
    AssetFileDescriptor d = context.getAssets().openFd(fileName);
    mp.reset();
    mp.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    mp.prepare();
    int duration = mp.getDuration();
    // ...
}

顺便说一下,这个问题已经被提出了但没有得到答案


你考虑过使用 onCompletionListener 吗?https://developer.android.com/reference/android/media/MediaPlayer.OnCompletionListener.html#onCompletion%28android.media.MediaPlayer%29 - sschrass
@SatelliteSD 在我拥有的任何设备上,它都根本不起作用(从未被调用过)。即使在某些操作系统版本/某些设备上被调用,它也是不可靠的,因此毫无用处。 - Gilead
1
你确认在.start()之后调用了setOnCompletionListener吗? - sschrass
完成监听器仅用于MediaPlayer,而不是SoundPool。据我所知,唯一的方法是使用MediaPlayer而不是SoundPool来回调声音完成时的情况。 - Matt Gibson
3个回答

15

你试过这个吗:

String mediaPath = Uri.parse("android.resource://<your-package-name>/raw/filename").getPath();
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(mediaPath);
String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
mmr.release();

但我并不确定这比现有的代码更轻。


3
别忘了释放MediaMetadataRetriever。 - Mihai Popescu
2
我尝试过这个,但每次都会从mmr.setDataSource()抛出IllegalArgumentException - 有没有办法找出路径应该长什么样子?因为我怀疑我使用的路径可能是不正确的。我正在使用捆绑在内的.m4a和/或.wav音频文件。 - Jonny
有没有办法在不下载文件的情况下检查URL的持续时间? - VikaS GuttE

4

试试FFmpegMediaMetadataRetriever

String[] fileNames = ...
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();

for (String fileName : fileNames) {
    AssetFileDescriptor d = context.getAssets().openFd(fileName);
    mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    String duration = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION);
}

mmr.release();

3
这是关于获取音频文件总时长的工作,单位为秒。
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
AssetFileDescriptor d = context.getAssets().openFd(fileName);
mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
String duration = 
mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
mmr.release();

已更新

获取资源音频文件时长的方法(秒)

  public String gettotaltimeassets() {

   MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    AssetFileDescriptor d = null;
    try {
        d = getApplicationContext().getAssets().openFd("ASSETS FILE NAME");
    } catch (IOException e) {
        e.printStackTrace();
    }
    mmr.setDataSource(d.getFileDescriptor(), d.getStartOffset(), d.getLength());
    String duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
    long dur = Long.parseLong(duration);
    String seconds = String.valueOf((dur % 60000) / 1000);
    Log.d("seconds===========>", seconds);
    mmr.release();
    return  seconds;
}

获取内部存储音频文件时长的方法(单位为秒)。
public String gettotaltimestorage(String filePath) {
    // load data file
    Log.d("time=================>","time=================>");
    MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
    metaRetriever.setDataSource(YourACTIVITY.this, Uri.parse(filePath));
    Log.d("time=================>","time=================>");
    String out = "";
    // get mp3 info

    // convert duration to minute:seconds
    String duration =
            metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
    Log.d("time=================>", duration);
    long dur = Long.parseLong(duration);
    String seconds = String.valueOf((dur % 60000) / 1000);
    Log.d("seconds===========>", seconds);
    // close object
    metaRetriever.release();
    return  seconds;

}

请解释你的答案。这不仅有助于理解当前问题的原因,还可以避免将来出现相同的问题。 - Dhaval Simaria
实际上,我编写了代码来获取资产中任何音频文件的持续时间,就像@William Seemann所写的那样,但我使用MediaMetadata来检索持续时间...我修改了我的答案,以便您更好地理解...您可以调用此方法来获取多个音频文件的持续时间。 - Manthan Patel
我没有写那个评论是因为我无法理解你的代码,但是在SO上附上适当的解释是一个好习惯。只有代码的答案不是受到高度欣赏的。 - Dhaval Simaria

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