我正在尝试使用AudioInputStream
跳过负数的字节
skip(long bytes)
方法。
问题正在尝试(假设有少量字节...):
int skipped = audioInputStream.skip(-bytes);
总是返回0,如答案Java AudioInputStream skip with negative number of bytes always returns 0所述
我需要创建一个实现,该实现还支持负数的字节或类似向后的内容。
Here is the full code的github库。
我要做的是每次用户跳过音频时都重新创建线路 当我当然可以做得更好的时候,这会非常慢... ...向前还是向后。现在它仅支持转发...
/**
* Skip bytes in the File input stream. It will skip N frames matching to bytes, so it will never skip given bytes len
*
* @param bytes
* the bytes
* @return value bigger than 0 for File and value = 0 for URL and InputStream
* @throws StreamPlayerException
* the stream player exception
*/
public long seek(long bytes) throws StreamPlayerException {
long totalSkipped = 0;
//If it is File
if (dataSource instanceof File) {
//Check if the requested bytes are more than totalBytes of Audio
long bytesLength = getTotalBytes();
System.out.println("Bytes: " + bytes + " BytesLength: " + bytesLength);
if ( ( bytesLength <= 0 ) || ( bytes >= bytesLength )) {
generateEvent(Status.EOM, getEncodedStreamPosition(), null);
return totalSkipped;
}
logger.info(() -> "Bytes to skip : " + bytes);
Status previousStatus = status;
status = Status.SEEKING;
try {
synchronized (audioLock) {
generateEvent(Status.SEEKING, AudioSystem.NOT_SPECIFIED, null);
initAudioInputStream();
if (audioInputStream != null) {
long skipped;
// Loop until bytes are really skipped.
while (totalSkipped < ( bytes )) { //totalSkipped < (bytes-SKIP_INACCURACY_SIZE)))
//System.out.println("Running");
skipped = audioInputStream.skip(bytes - totalSkipped);
if (skipped == 0)
break;
totalSkipped += skipped;
logger.info("Skipped : " + totalSkipped + "/" + bytes);
if (totalSkipped == -1)
throw new StreamPlayerException(StreamPlayerException.PlayerException.SKIP_NOT_SUPPORTED);
logger.info("Skeeping:" + totalSkipped);
}
}
}
generateEvent(Status.SEEKED, getEncodedStreamPosition(), null);
status = Status.OPENED;
if (previousStatus == Status.PLAYING)
play();
else if (previousStatus == Status.PAUSED) {
play();
pause();
}
} catch (IOException ex) {
logger.log(Level.WARNING, ex.getMessage(), ex);
}
}
return totalSkipped;
}
答案 0 :(得分:2)
您可以创建自己的缓冲区,它可以是ByteArrayOutputStream,但这是个a肿的事情-几分钟后总是让我内存不足-或拥有自己的Vector或其他ArrayList。
我尝试了一个10分钟的.wav文件,该文件运行良好-可以播放并将字节添加到缓冲区。
例如
Vector v=new Vector();
byte[] data=new byte[basicU];
while(true) {
k=audioInputStream.read(data, 0, data.length);
v.add(data);
if(k<0) break;
tot+=k;
}
-
这是我用于播放带有搜索文件的方法。我有一个用于生成寻道信号的线程。当我们进行多次搜索时,问题就变得复杂了。我使用变量K来检查是否需要向缓冲区添加数据。我不使用跳过,而是正常阅读;只是不要在线播放。
public void play() {
boolean seekingBack=false;
int i, j, k=0, seekPos=0, basicU=1024;
AudioFormat targetFormat=null;
int tot=0;
new Thread() {
public void run() {
while(true) {
numBytes=(Math.random()>0.5?1:-1)*500000;
try { Thread.sleep(5000); } catch (Exception e) {}
seekSignal=true;
}
}}.start();
try {
File fileIn=new File("........");
AudioInputStream audioInputStream=AudioSystem.getAudioInputStream(fileIn);
targetFormat=audioInputStream.getFormat();
DataLine.Info dinfo=new DataLine.Info(SourceDataLine.class, targetFormat);
SourceDataLine line=null;
line=(SourceDataLine)AudioSystem.getLine(dinfo);
if(line==null) return;
line.open(targetFormat);
line.start();
Vector v=new Vector();
byte[] data=new byte[basicU];
int K=0;
while(true) {
if(seekingBack) { // seeking backwards
K=seekPos;
k=data.length;
for(j=0; j<data.length; j++)
if(seekPos+j<v.size()) data[j]=((Byte)v.get(seekPos+j)).byteValue();
else { k=j; break; }
line.write(data, 0, k);
seekPos+=k;
K+=k;
if(seekPos>v.size()-1) seekingBack=false;
}
else { // normal playing
k=audioInputStream.read(data, 0, data.length);
if(k<0) break;
line.write(data, 0, k);
if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
K+=k;
}
if(seekSignal) { // received a seek signal
if(seekingBack) { // we are on a previous back seek - reading from the buffer
if(numBytes<0) {
seekPos+=numBytes;
if(seekPos<0) seekPos=0;
}
else { // depending on where the seek will go (in the buffer or actual audio stream)
if(numBytes+seekPos<v.size())
seekPos+=numBytes;
else { // actual stream
int rem=numBytes-(v.size()-seekPos);
K=v.size();
while(rem>0) {
k=audioInputStream.read(data, 0, data.length);
if(k<0) break;
if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
rem-=k;
K+=k;
}
}
}
}
else { // we are not processing a previous back seek
if(numBytes>=0) { // forward
while(numBytes>0) {
k=audioInputStream.read(data, 0, data.length);
if(k<0) break;
if(K>=v.size()) for(j=0; j<k; j++) v.add(data[j]);
numBytes-=k;
K+=k;
}
}
else { // backward
seekingBack=true; seekPos=v.size()+numBytes; if(seekPos<0) seekPos=0; }
}
seekSignal=false;
}
}
line.stop();
line.close();
}
catch(Exception ex) { ex.printStackTrace(); System.out.println("audio problem "+ex); }
}
答案 1 :(得分:0)
使用您自己的缓冲区来保存历史记录的滚动窗口。我将构建一个帮助程序类,通过分配List<byte[]>
来管理历史记录,例如以8192字节为块。然后,您需要一些简单的溢出机制来抛出最旧的块,并结合一些指针操作来跟踪您实际在流中的位置。祝你好运!