java播放MP3长度不对

符千青 2016-07-11 10:47:28
我在论坛上找了一段播放MP3的代码,,,现在我想加一个显示播放进度的进步条。。。然后我发现同一个输入流在两个地方读到的长度居然不一样

package com.inkbox.music;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.awt.BorderLayout;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.List;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.MenuShortcut;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.swing.JButton;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.Header;

@SuppressWarnings("serial")
public class MusicPlayer extends Frame {
boolean isStop = true; // 控制播放线程
boolean hasStop = true; // 播放线程状态
String filepath; // 播放文件目录
String filename; // 播放文件名称
long audioLength = 0;// 音频总长度
long playLength = 0;// 记录已播放长度
List list;// 文件列表
Label labelfilepath; // 播放目录显示标签
Label labelfilename; // 播放文件显示标签

AudioInputStream audioInputStream; // 文件流
AudioFormat audioFormat; // 文件格式
SourceDataLine sourceDataLine; // 输出设备

public MusicPlayer() {
try {
UIManager.setLookAndFeel("com.jtattoo.plaf.acryl.AcrylLookAndFeel");
// new AlloyLookAndFeel().
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
// 设置窗体属性
setLayout(new BorderLayout());
setTitle("MP3音乐播放器");
setSize(350, 370);
// 建立菜单栏
MenuBar menubar = new MenuBar();
Menu menufile = new Menu("文件");
MenuItem menuopen = new MenuItem("打开", new MenuShortcut(KeyEvent.VK_O));
menufile.add(menuopen);
menufile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
open();
}
});
menubar.add(menufile);
setMenuBar(menubar);
// 文件列表
list = new List(10);
list.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
// 双击时处理
if (e.getClickCount() == 2) {
// 播放选中的文件
filename = list.getSelectedItem();

play();
}
}
});
add(list, "Center");
// 信息显示
Panel panel = new Panel(new GridLayout(4, 1));
labelfilepath = new Label("播放目录:");
panel.add(labelfilepath);

button = new JButton("\u6682\u505C");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized (playThread) {
pause = !pause;
}

}
});
labelfilename = new Label("播放文件:");
panel.add(labelfilename);
panel.add(button);

progressBar = new JProgressBar();
progressBar.setStringPainted(true);
panel.add(progressBar);
add(panel, "North"); // 注册窗体关闭事件
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setVisible(true);
}

// 打开
private void open() {
FileDialog dialog = new FileDialog(this, "Open", 0);
dialog.setVisible(true);
filepath = dialog.getDirectory();
if (filepath != null) {
labelfilepath.setText("播放目录:" + filepath);
// 显示文件列表
list.removeAll();
File filedir = new File(filepath);
File[] filelist = filedir.listFiles();
for (File file : filelist) {
String filename = file.getName().toLowerCase();
if (filename.endsWith(".mp3") || filename.endsWith(".wav")) {
list.add(filename);
}
}
}
}

// 播放
private void play() {
try {
isStop = true;
// 停止播放线程
// 等待播放线程停止,等待已播放歌曲停止
System.out.print("开始播放:" + filename);
while (!hasStop) {
System.out.print(".");
try {
Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("");

File file = new File(filepath + filename);
// audioLength = file.length();
labelfilename.setText("播放文件:" + filename);
FileInputStream fis = new FileInputStream(file);
int b = fis.available();
Bitstream bt = new Bitstream(fis);
Header h = bt.readFrame();
int time = (int) h.total_ms(b);

int i = time / 1000;
System.out.println(i / 60 + ":" + i % 60);

// 取得文件输入流
audioInputStream = AudioSystem.getAudioInputStream(file);
audioFormat = audioInputStream.getFormat();
audioLength = getLength();
System.out.println(audioLength);
audioInputStream = AudioSystem.getAudioInputStream(file);

// 转换MP3文件编码
if (audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) {
audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
audioFormat.getSampleRate(), 16,
audioFormat.getChannels(),
audioFormat.getChannels() * 2,
audioFormat.getSampleRate(), false);
audioInputStream = AudioSystem.getAudioInputStream(audioFormat,
audioInputStream);
}

// 打开输出设备
DataLine.Info dataLineInfo = new DataLine.Info(
SourceDataLine.class, audioFormat,
AudioSystem.NOT_SPECIFIED);
sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
sourceDataLine.open(audioFormat);
sourceDataLine.start();
// 创建独立线程进行播放
isStop = false;
playThread = new Thread(new PlayThread());
playThread.start();
} catch (Exception e) {
e.printStackTrace();
}
}

Thread playThread;

public static void main(String args[]) {
new MusicPlayer();
// AudioFilePlayer asp=new AudioFilePlayer();
// asp.play("E:\\music\\郁可唯 - 暖心.mp3");
}

boolean pause = false;
private JButton button;
private JProgressBar progressBar;

class PlayThread extends Thread {
byte tempBuffer[] = new byte[320];
public void run() {
try {
int cnt;
hasStop = false;
int readTime = 0;
int writeTime = 0;
playLength = 0;
int pl=0;
while (true) {
// 读取数据到缓存数据
// while ((cnt = audioInputStream.read(tempBuffer, 0,
// tempBuffer.length)) != -1) {
// System.out.println("线程未死");
Thread.sleep(1);// 稍微等待,否则暂停后无法重启,不宜过久,否则声音不连续
if (!pause) {
cnt = audioInputStream.read(tempBuffer, 0,
tempBuffer.length);
readTime++;

if (cnt == -1) {
break;
}
pl+=cnt;
if (cnt > 0) {
int writeLength = sourceDataLine.write(tempBuffer,
0, cnt);
writeTime++;
// write(playLength);
// 写入的数据总会大于文件总长度
playLength += writeLength;
float d_audioLength = (float) (audioLength / 100);
float d_playLength = (float) (playLength / 100);
float d = d_playLength / d_audioLength * 100;
// System.out.println("pl=" + pl
// + " audioLength=" + audioLength
// + " playLength=" + playLength + " 百分比="
// + d + " writeLenght=" + writeLength);
// pause = true;
progressBar.setValue((int) d);

// 写入缓存数据
}
}
// 无论此时是否处于暂停状态,换歌的时候都需要停止当前线程
if (isStop) {
if (pause) {
pause = false;
}
playLength = 0;
break;
}
}
// Block等待临时数据被输出为空
sourceDataLine.drain();
sourceDataLine.close();
hasStop = true;
System.out.println("播放结束--pause=" + pause);
System.out.println("writeTime=" + writeTime + " readTime="
+ readTime);
System.out.println("audioLenget=" + audioLength
+ " playLength=" + playLength);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}

public long getLength() {
long len = 0;

byte btes[] = new byte[320];
int temp = 0;
int time=0;
try {
while ((temp = audioInputStream.read(btes, 0, btes.length)) != -1) {
len += temp;
time++;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
audioInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("len="+len+" time="+time);
return len;
}

}


我发现 run() 方法里的循环次数是 getLength() 方法的 十倍 多,,,最后往输出设备输出的 字节数,大于了文件总字节长度

如果又读又写就会比只读循环次数多出十倍

为什么同一个流居然会有不同的长度呢
...全文
275 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
符千青 2016-07-11
  • 打赏
  • 举报
回复

62,634

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧