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


我正在使用 的Soundpool  在我的应用程序中播放音频剪辑。一切都很好,但我需要知道剪辑播放何时完成。

目前我在我的应用程序中通过使用a获取每个剪辑的持续时间来跟踪它 媒体播放器 实例。这工作正常,但加载每个文件两次看起来很浪费,只是为了得到持续时间。我可以自己大致计算持续时间,知道文件的长度(可从中获取) AssetFileDescriptor)但我仍然需要知道采样率和通道数。

我看到了这个问题的两种可能解决方案:

  1. 弄清楚剪辑何时播放完毕(SoundClip似乎无法实现)。
  2. 有一个类可以只加载音频文件的标题,并给我采样率/通道数(理想情况下,样本计数,以获得确切的持续时间)。

有什么建议么?

谢谢, 马克斯

我目前正在使用的代码(工作正常,但为此目的相当沉重):

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();
    // ...
}

另一方面,这个问题已经存在  但没有答案。


4190
2018-01-17 03:46


起源

你有没有考虑过 onCompletitionListener? developer.android.com/reference/android/media/... - sschrass
@SatelliteSD它在我拥有的任何设备上都无法工作(永远不会被调用)。即使在某些操作系统版本/某些设备上调用它也不可靠,因此无用。 - Gilead
你仔细检查了一下 setOnCompletitionListner 被称为 .start()? - sschrass
完成侦听器仅用于MediaPlayer,而不用于SoundPool。据我所知,在声音处理上进行回调的唯一方法是使用MediaPlayer,而不是SoundPool。 - Matt Gibson


答案:


你试过这个:

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();

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


10
2017-07-16 19:04



别忘了发布 MediaMetadataRetriever - Mihai Popescu
我试过这个,但我总是抛出一个IllegalArgumentException mmr.setDataSource()  - 有没有办法找出这条路应该是什么样子?因为我怀疑我使用的路径可能不正确。我正在使用in-bundle .m4a和/或.wav音频文件。 - Jonny
@Meher完美答案+1 - Harin Kaklotar
不为我工作总是得到持续时间0 - praveen s


尝试 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
2017-07-17 18:52





这对我来说可以在几秒钟内获得资产音频文件的持续时间=====>

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;

}

0
2017-08-17 06:20



请解释你的答案。这不仅有助于了解当前问题的原因,而且有助于避免将来出现问题。 - Dhaval Simaria
实际上我编写代码来获取资产中任何音频文件的持续时间@William Seemann写,但我使用MediaMetadata来检索持续时间...我修改我的答案让你理解得更好...你可以调用这个方法来获取多个音频文件持续时间。 - Manthan Patel
我没有写那条评论,因为我无法理解你的代码,但是在SO上为你的解决方案提供正确的解释是一个很好的做法。仅代码答案不受高度赞赏。 - Dhaval Simaria