如何在JLayer中获取播放器当前帧并实现pause()方法
实现JLayer AdvancedPlayer的暂停/续播功能
我正在用Java编写一款MP3播放器,希望实现pause()方法存储AdvancedPlayer停止时的播放帧,resume()方法从该帧继续播放。但现有的JLayer库(umjammer/jlayer分支)中,Player类只有getFrame()方法,没有支持从指定帧开始播放的play()方法,无法执行play(fromThisFrame, Integer.MAX_VALUE)这类操作。尝试过切换JavaFX但编译失败,阅读库源码、重构代码都没解决问题,这是课程作业的测试分支,仅需实现基础功能。
现有代码
AudioHandler类
public class AudioHandler { private AdvancedPlayer player; private Thread playThread; Bitstream stream; private boolean playing = false; private boolean paused; private int pausedOnFrame; private Track currTrack; /* * Handling the playing of an mp3 instance * @param track Track instance that carries the path that the player can play */ public void play(Track track){ String path = track.getPath(); currTrack = track; if(!playing){ playing = true; paused = false; pausedOnFrame = 0; // Thread handling is needed cause I will implement a SwiftGUI playThread = new Thread(() -> { try(FileInputStream fis = new FileInputStream(path)) { stream = new Bitstream(fis); player = new AdvancedPlayer(fis); player.play(pausedOnFrame, Integer.MAX_VALUE); } catch (JavaLayerException | IOException e) { e.printStackTrace(); } finally{ playing = false; pausedOnFrame = 0; } }); playThread.start(); } else System.out.println("Already playing."); } /* * Stops the thread and the player * Sets the playing to false */ public void stop() { // ... } /* * Sets the paused to true * Closes the player == pauses the player at the frame */ public void pause() throws BitstreamException { if (playing && !paused) { System.out.println(stream.readFrame()); player.close(); paused = true; } } /* * Resumes playback from where it was paused */ public void resume() { if (paused) { paused = false; play(currTrack, pausedOnFrame); // Start playing again from the saved path } } }
Main类
import java.io.*; public class Main { public static void main(String[] args) { try{ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); // 修正语法错误:假设Track有接收路径的构造方法 Track asd = new Track("/path/to/song.mp3"); AudioHandler plr = new AudioHandler(); String input; while(true){ input = reader.readLine(); if(input.equals("exit")) System.exit(0); if(input.equals("play")) plr.play(asd); if(input.equals("stop")) plr.stop(); if(input.equals("pause")) plr.pause(); if(input.equals("resume")) plr.resume(); } } catch(Exception e){} } }
解决方案
针对umjammer/jlayer库,我们可以通过自定义AdvancedPlayer子类统计已播放帧数,并在续播时跳过对应帧数的方式实现暂停/续播功能,具体修改如下:
1. 修改AudioHandler成员变量
添加记录已播放帧数的变量:
public class AudioHandler { private AdvancedPlayer player; private Thread playThread; Bitstream stream; private boolean playing = false; private boolean paused; private int playedFrames = 0; // 新增:记录已播放帧数 private Track currTrack; // ... 其他代码 }
2. 自定义CountingAdvancedPlayer子类
在AudioHandler内部定义继承自AdvancedPlayer的子类,用于统计已播放帧数:
private class CountingAdvancedPlayer extends AdvancedPlayer { private volatile int framesPlayed = 0; public CountingAdvancedPlayer(InputStream in) throws JavaLayerException { super(in); } @Override protected boolean decodeFrame() throws JavaLayerException { boolean decoded = super.decodeFrame(); if (decoded) { framesPlayed++; } return decoded; } public int getFramesPlayed() { return framesPlayed; } }
3. 重构play方法,支持起始帧偏移
添加重载的play方法,实现从指定帧开始播放的逻辑:
// 原有play方法,默认从第0帧开始 public void play(Track track){ play(track, 0); } // 新增重载方法,支持从指定帧开始播放 public void play(Track track, int startFrame){ String path = track.getPath(); currTrack = track; if(!playing){ playing = true; paused = false; playedFrames = startFrame; playThread = new Thread(() -> { try(FileInputStream fis = new FileInputStream(path)) { // 使用自定义的计数播放器 player = new CountingAdvancedPlayer(fis); // 跳过起始帧之前的所有帧 skipFrames(startFrame); // 播放剩余所有帧 player.play(Integer.MAX_VALUE); } catch (JavaLayerException | IOException e) { e.printStackTrace(); } finally{ playing = false; // 非暂停状态下重置计数 if(!paused){ playedFrames = 0; } } }); playThread.start(); } else System.out.println("Already playing."); } // 新增跳过指定帧数的方法 private void skipFrames(int frames) throws JavaLayerException { if(frames <= 0) return; Bitstream bitstream = ((CountingAdvancedPlayer) player).getBitstream(); for(int i=0; i<frames; i++){ Header header = bitstream.readFrame(); if(header == null){ break; // 到达文件末尾,停止跳过 } bitstream.closeFrame(); } }
4. 修改pause方法,记录暂停时的帧数
在暂停时停止播放器并记录当前已播放帧数:
public void pause() throws JavaLayerException { if (playing && !paused) { player.stop(); // 停止播放 // 记录当前已播放帧数 playedFrames = ((CountingAdvancedPlayer) player).getFramesPlayed(); player.close(); paused = true; playing = false; } }
5. 修改resume方法,从记录的帧数续播
直接调用重载的play方法,传入记录的起始帧:
public void resume() { if (paused) { paused = false; play(currTrack, playedFrames); } }
内容的提问来源于stack exchange,提问作者AutisticAllosaurus
相关产品推荐
相关产品推荐

