(我正在尝试使上一个问题更通用,以期找到解决方案。)
我正在使用JLayer库和sample.mp3文件。我想同时播放和解码文件。
但是,我希望它们被同步-如果歌曲的一部分被解码,它也会被播放。在播放之前,不会解码任何内容,反之亦然(当然,在一定程度上)。
请分别按以下步骤播放和解码歌曲:
Player p = new Player(InputStream mp3stream);
p.play();
Decoder d = new Decoder();
BitStream bs = new Bitstream(InputStream mp3stream);
SampleBuffer s = (SampleBuffer) d.decodeFrame(bs.readFrame(), bs);
// ... for processing the SampleBuffer but irrelevant for the question
我目前使用:
InputStream mp3stream = new FileInputStream("sample.mp3");
但这会立即使用整首歌曲,因此我无法同步。有没有一种方法可以将sample.mp3分成两个过程都可以操纵的片段?如果我有足够多的小片段,我可以将两个片段都放入流程中,等到两个片段都完成后再抓取下一个小片段,然后重复进行直到我没有小片段为止。
注意:我尝试使用ByteArrayInputStream失败,但可能在使用时不正确。
最佳答案
我希望我做对了:
您只有一个输入文件
您希望两个不同的输入流在某种意义上是同步的,即“它们必须取得相同的进度”。
这是一个有趣的问题。我提出了以下草图(可编译,但未执行,因此您可能需要先进行一些测试)。
创建一个包装对象“ StreamSynchronizer”,该对象控制对基础输入的访问。仅读取一个字节,直到所有派生流都读取了该字节。
从中派生任意数量的“ SynchronizedStream”实例,这些实例委派了“读”回StreamSynchronizer。
package de.mit.stackoverflow;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class StreamSynchronizer {
final private InputStream inputStream;
private List activeStreams = new ArrayList();
private int lastByte;
private Set waitingStreams = new HashSet();
private Object lock = new Object();
public StreamSynchronizer(InputStream is) throws IOException {
super();
this.inputStream = is;
lastByte = getInputStream().read();
}
public void close(SynchronizedStream stream) {
activeStreams.remove(stream);
}
public SynchronizedStream createStream() {
SynchronizedStream stream = new SynchronizedStream(this);
activeStreams.add(stream);
return stream;
}
public InputStream getInputStream() {
return inputStream;
}
public int read(SynchronizedStream stream) throws IOException {
synchronized (lock) {
while (waitingStreams.contains(stream)) {
if (waitingStreams.size() == activeStreams.size()) {
waitingStreams.clear();
lastByte = getInputStream().read();
lock.notifyAll();
} else {
try {
lock.wait();
} catch (InterruptedException e) {
throw new IOException(e);
}
}
}
waitingStreams.add(stream);
return lastByte;
}
}
}
package de.mit.stackoverflow;
import java.io.IOException;
import java.io.InputStream;
public class SynchronizedStream extends InputStream {
final private StreamSynchronizer synchronizer;
protected SynchronizedStream(StreamSynchronizer synchronizer) {
this.synchronizer = synchronizer;
}
@Override
public void close() throws IOException {
getSynchronizer().close(this);
}
public StreamSynchronizer getSynchronizer() {
return synchronizer;
}
@Override
public int read() throws IOException {
return getSynchronizer().read(this);
}
}