You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取JavaZoom AdvancedPlayer的已播放音频帧数

如何获取JavaZoom AdvancedPlayer的已播放音频帧数

我太懂你现在的困扰了——用JavaZoom AdvancedPlayer做带进度滑块的音频播放器时,总帧数能正常获取,但已播放帧数总是不准,而且你还想用skippedFrames变量来处理滑块点击后的跳转逻辑对吧?

其实AdvancedPlayer本身并没有直接提供获取已播放帧数的API,我们得自己做个小包装来统计读取的音频帧,下面是具体的解决方法:

  • 自定义计数型AudioInputStream
    我们可以写一个包装类,继承AudioInputStream,在读取音频数据的时候自动统计已读取的帧数,还能避免多线程播放时的计数混乱:

    import javax.sound.sampled.AudioInputStream;
    import java.io.IOException;
    import java.util.concurrent.atomic.AtomicLong;
    
    public class CountingAudioInputStream extends AudioInputStream {
        private final AtomicLong framesRead = new AtomicLong(0);
        private final AudioInputStream delegate;
    
        public CountingAudioInputStream(AudioInputStream delegate) {
            super(delegate, delegate.getFormat(), delegate.getFrameLength());
            this.delegate = delegate;
        }
    
        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            int bytesRead = delegate.read(b, off, len);
            if (bytesRead > 0) {
                // 按每帧字节数计算读取的帧数,用AtomicLong保证线程安全
                framesRead.addAndGet(bytesRead / getFormat().getFrameSize());
            }
            return bytesRead;
        }
    
        public long getFramesRead() {
            return framesRead.get();
        }
    
        // 用于跳转后同步帧数
        public void setFramesRead(long frames) {
            framesRead.set(frames);
        }
    }
    
  • 替换原输入流并初始化播放器
    把原来的AudioInputStream替换成我们的计数版本,这样播放时就能自动统计帧数了:

    import javax.sound.sampled.AudioInputStream;
    import javax.sound.sampled.AudioSystem;
    import javazoom.jl.player.advanced.AdvancedPlayer;
    import java.io.File;
    
    // 初始化示例
    File audioFile = new File("your-audio-file.mp3");
    AudioInputStream originalStream = AudioSystem.getAudioInputStream(audioFile);
    CountingAudioInputStream countingStream = new CountingAudioInputStream(originalStream);
    AdvancedPlayer player = new AdvancedPlayer(countingStream);
    
  • 同步跳转后的帧数计数
    当你通过滑块点击调用seekTo(targetTime)时,别忘了同步更新计数的帧数,不然之前的统计会和实际播放位置脱节:

    public void seekTo(long targetTimeMs) {
        float sampleRate = countingStream.getFormat().getSampleRate();
        // 计算目标时间对应的帧数
        long targetFrames = (long) (targetTimeMs * sampleRate / 1000);
        // 计算需要跳过的帧数
        long framesToSkip = targetFrames - countingStream.getFramesRead();
        
        // 执行跳转(这里假设你的skipFrames逻辑是正常的)
        skippedFrames = player.skip((int) framesToSkip);
        // 同步更新计数的帧数,确保后续统计准确
        countingStream.setFramesRead(targetFrames);
    }
    
  • 实时获取已播放帧数
    之后你就可以在需要更新滑块进度的地方,调用countingStream.getFramesRead()拿到准确的已播放帧数,和总帧数(countingStream.getFrameLength())对比就能算出当前播放进度了。

备注:内容来源于stack exchange,提问作者Artik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 15:59:42