0

我正在尝试在 Raspberry Pi 上使用 GStreamer Java Binding 来播放一些经过 Opus 编码的动态音频数据。我马上就好。我的最后一个问题是,当数据到达末尾时,我无法让 GStreamer 很好地清理。我的测试代码如下。

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();
            }
        });
    }

}

我不使用 playbin,因为音频数据最终会以字节流的形式出现。

测试运行良好,直到结束。当我到达文件末尾时。我收到错误消息并跟随 JVM 迷恋。错误信息是这样的:

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed Returned, stopping playback

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed

(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed

(AudioTest:4643): GLib-GObject-CRITICAL **: g_value_set_object: assertion 'G_IS_OBJECT (v_object)' failed
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x63d8b8ec, pid=4643, tid=1658819680
#
# JRE version: Java(TM) SE Runtime Environment (8.0_65-b17) (build
1.8.0_65-b17)
# Java VM: Java HotSpot(TM) Client VM (25.65-b01 mixed mode linux-arm )
# Problematic frame:
# C  [libglib-2.0.so.0+0x928ec]  g_rec_mutex_lock+0x8
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/pi/gstJavaTest/hs_err_pid4643.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
# Aborted

我找不到任何关于使用 AppSrc 结束播放的示例。任何帮助将不胜感激。

4

1 回答 1

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();
                }
            }
于 2016-06-01T13:44:16.483 回答