我正在尝试在Raspberry Pi上使用GStreamer Java Binding来播放一些Opus编码的动态音频数据。我就快完成了。我的最后一个问题是,当数据到达终点时,我不能很好地清理GStreamer。我的测试代码如下。
MusicPlayer
我不使用playbin,因为音频数据最终将以字节流的形式出现。
测试运行良好直至结束。当我到达文件的末尾。我得到错误消息,并遵循JVM粉碎。错误消息如下:
package org.freedesktop.gstreamer.examples;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.swing.JFrame;
import org.freedesktop.gstreamer.Bin;
import org.freedesktop.gstreamer.Buffer;
import org.freedesktop.gstreamer.Bus;
import org.freedesktop.gstreamer.Element;
import org.freedesktop.gstreamer.ElementFactory;
import org.freedesktop.gstreamer.FlowReturn;
import org.freedesktop.gstreamer.Gst;
import org.freedesktop.gstreamer.GstObject;
import org.freedesktop.gstreamer.Message;
import org.freedesktop.gstreamer.Pad;
import org.freedesktop.gstreamer.PadLinkReturn;
import org.freedesktop.gstreamer.Pipeline;
import org.freedesktop.gstreamer.State;
import org.freedesktop.gstreamer.elements.AppSrc;
import org.freedesktop.gstreamer.lowlevel.MainLoop;
/**
*
* @author Superrei
*/
public class AudioTest {
//private static final int BUFFER_SIZE = 4096;
private static byte[] soundBytes = null;
private static int pointer = 0;
private static String filename = null;
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Gst.init("AudioTest", args);
filename = args[0];
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
File soundFile = new File(filename);
FileInputStream inStream = null;
if (soundFile.exists()){
try {
System.out.println("Read media file.");
long fileSize = soundFile.length();
soundBytes = new byte[(int)fileSize];
inStream = new FileInputStream(soundFile);
int byteCount = inStream.read(soundBytes);
System.out.println("Number of byte read: " + byteCount);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
final MainLoop loop = new MainLoop();
AppSrc source = (AppSrc)ElementFactory.make("appsrc", "app-source");
Element demuxer = ElementFactory.make("oggdemux", "ogg-demuxer");
final Element decoder = ElementFactory.make("opusdec", "opus-decoder");
Element conv = ElementFactory.make("audioconvert", "converter");
Element sink = ElementFactory.make("autoaudiosink", "audio-output");
//source.set("location", "/home/pi/gstJavaTest/transcript.ogg");
Pipeline pipe = new Pipeline();
Bus bus = pipe.getBus();
bus.connect(new Bus.EOS() {
@Override
public void endOfStream(GstObject source) {
loop.quit();
}
});
bus.connect(new Bus.ERROR() {
@Override
public void errorMessage(GstObject source, int code, String message) {
System.out.println("Error detected");
System.out.println("Error source: " + source.getName());
System.out.println("Error code: " + code);
System.out.println("Message: " + message);
loop.quit();
}
});
pipe.addMany(source, demuxer, decoder, conv, sink);
source.link(demuxer);
source.set("emit-signals", true);
source.connect(new AppSrc.NEED_DATA() {
private ByteBuffer bb = ByteBuffer.wrap(soundBytes);
@Override
public void needData(AppSrc elem, int size) {
if (bb.hasRemaining()) {
// TODO Auto-generated method stub
System.out.println("needData: size = " + size);
byte[] tempBuffer;
Buffer buf;
if (bb.remaining() > size) {
tempBuffer = new byte[size];
buf = new Buffer(size);
} else {
tempBuffer = new byte[bb.remaining()];
buf = new Buffer(bb.remaining());
}
//System.out.println("Buffer size: " + buf.map(true).remaining());
//System.arraycopy(soundBytes, pointer, tempBuffer, 0, size);
bb.get(tempBuffer);
System.out.println("Temp Buffer remaining bytes: " + bb.remaining());
buf.map(true).put(ByteBuffer.wrap(tempBuffer));
elem.pushBuffer(buf);
} else {
elem.emit("end-of-stream", elem);
}
//pointer += size;
}
});
source.connect(new AppSrc.ENOUGH_DATA() {
@Override
public void enoughData(AppSrc elem) {
System.out.println("enoughData: " + elem.toString());
}
});
source.connect(new AppSrc.END_OF_STREAM() {
@Override
public FlowReturn endOfStream(AppSrc elem) {
// TODO Auto-generated method stub
return FlowReturn.OK;
}
});
Element.linkMany(decoder, conv, sink);
demuxer.connect(new Element.PAD_ADDED() {
@Override
public void padAdded(Element element, Pad pad) {
System.out.println("Dynamic pad created, linking demuxer/decoder");
System.out.println("Pad name: " + pad.getName());
System.out.println("Pad type: " + pad.getTypeName());
Pad sinkPad = decoder.getStaticPad("sink");
//boolean linked = element.link(decoder);
PadLinkReturn ret = pad.link(sinkPad);
if (ret.equals(PadLinkReturn.OK)){
System.out.println("Pad linked.");
} else {
System.out.println("Pad link failed");
}
//System.out.println("Pad Link Return: " + ret.toString());
}
});
System.out.println("Now Playing...");
pipe.play();
System.out.println("Running...");
loop.run();
System.out.println("Returned, stopping playback");
pipe.stop();
}
});
}
}
我找不到任何使用AppSrc播放结尾的例子。任何帮助将不胜感激。
答案 0 :(得分:0)
我解决了这个问题。解决方案是使用AppSrc.endOfStream()
方法而不是发出信号。此外,我删除了AppSrc.END_OF_STREAM的回调,因为没有必要。所以我对needData的回调是这样的:
@Override
public void needData(AppSrc elem, int size) {
if (bb.hasRemaining()) {
System.out.println("needData: size = " + size);
byte[] tempBuffer;
Buffer buf;
int copyLength = (bb.remaining() >= size) ? size : bb.remaining();
tempBuffer = new byte[copyLength];
buf = new Buffer(copyLength);
//System.arraycopy(soundBytes, pointer, tempBuffer, 0, copyLength);
System.out.println("Buffer size: " + buf.map(true).remaining());
bb.get(tempBuffer);
System.out.println("Temp Buffer remaining bytes: " + bb.remaining());
buf.map(true).put(ByteBuffer.wrap(tempBuffer));
elem.pushBuffer(buf);
//pointer += size;
} else {
elem.endOfStream();
}
}