gstreamer-java/gst1-java-core

Trying to dispose element pipeline1, but it is in PLAYING instead of the NULL state.

sblantipodi opened this issue · 5 comments

Hi,
thanks for the wonderful work here guys.

Sometimes when capturing the screen I get this error:
Trying to dispose element pipeline1, but it is in PLAYING instead of the NULL state.

Is this a problem of the java bindings?

This is an example of my grabber, it's based on the library examples.

/**
 * This class needs GStreamer: open source multimedia framework
 * This class uses Windows Desktop Duplication API
 */
public class GStreamerGrabber extends javax.swing.JComponent {

    private final Lock bufferLock = new ReentrantLock();
    private final AppSink videosink;
    static LinkedHashMap<Integer, LEDCoordinate> ledMatrix;

    /**
     * Creates a new instance of GstVideoComponent
     */
    public GStreamerGrabber() {

        this(new AppSink("GstVideoComponent"));

    }

    /**
     * Creates a new instance of GstVideoComponent
     */
    public GStreamerGrabber(AppSink appsink) {

        this.videosink = appsink;
        videosink.set(Constants.EMIT_SIGNALS, true);
        AppSinkListener listener = new AppSinkListener();
        videosink.connect(listener);
        String gstreamerPipeline = Constants.GSTREAMER_PIPELINE;

            gstreamerPipeline += Constants.FRAMERATE_PLACEHOLDER.replaceAll("FRAMERATE_PLACEHOLDER", FireflyLuciferin.config.getDesiredFramerate());
       
        StringBuilder caps = new StringBuilder(gstreamerPipeline);
        // JNA creates ByteBuffer using native byte order, set masks according to that.
        if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
            caps.append(Constants.BYTE_ORDER_BGR);
        } else {
            caps.append(Constants.BYTE_ORDER_RGB);
        }
        videosink.setCaps(new Caps(caps.toString()));
        setLayout(null);
        setOpaque(false);
        setBackground(Color.BLACK);

    }

    /**
     * Return videosink element
     * @return videosink
     */
    public Element getElement() {

        return videosink;

    }

    /**
     * Listener callback triggered every frame
     */
    private class AppSinkListener implements AppSink.NEW_SAMPLE {

        public void rgbFrame(int width, int height, IntBuffer rgbBuffer) {

            // If the EDT is still copying data from the buffer, just drop this frame
            if (!bufferLock.tryLock()) {
                return;
            }

            int intBufferSize = (width*height)-1;

            try {
               my business with rgbBuffer
            } finally {
                bufferLock.unlock();
            }
        }

        /**
         * New sample triggered every frame
         * @param elem appvideosink
         * @return flow
         */
        @Override
        public FlowReturn newSample(AppSink elem) {
            Sample sample = elem.pullSample();
            Structure capsStruct = sample.getCaps().getStructure(0);
            int w = capsStruct.getInteger(Constants.WIDTH);
            int h = capsStruct.getInteger(Constants.HEIGHT);
            Buffer buffer = sample.getBuffer();
            ByteBuffer bb = buffer.map(false);
            if (bb != null) {
                rgbFrame(w, h, bb.asIntBuffer());
                buffer.unmap();
            }
            sample.dispose();
            return FlowReturn.OK;
        }

    }

}

This is almost certainly a bug in your code, in something not shared here. You must keep a strong reference to the pipeline, and anything that references that pipeline, or the garbage collector will attempt to clean up the pipeline you're using while it's running.

@neilcsmith-net my Pipeline is declared as static,
as much as I know static variables are not garbage collected.

are there something else that can throw that error?
thanks

problem happens when GStreamer "is suffering", for example when a videogame or something heavy is running on the GPU alongside with the dxgiscreencapsrc.
during the screen capture I can monitor the framerate and the framerate never goes down 9FPS.

if I close the game and the GPU is not loaded with other workloads,
the screen capture framerate returns to 30FPS and the problem never happen.

@sblantipodi unless you share that code, can't help you further, sorry. Either the GC is disposing the pipeline or something in your code is, before it's been stopped properly (also make sure to call stop() before disposing).

@neilcsmith-net you're always right, thanks for the help, I've seen that one of my executors where trying to play the same pipeline that is running.
problem solved, thanks for helping me finding the solution.

@sblantipodi 😄 no problem, this is a common error people encounter.