/* * Copyright (c) 2007,2008 Wayne Meissner * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2004,2005 Wim Taymans <wim@fluendo.com> * * This file is part of gstreamer-java. * * This code is free software: you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * version 3 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>. */ package org.gstreamer; import org.gstreamer.lowlevel.GstAPI.GErrorStruct; import org.gstreamer.lowlevel.GstElementAPI; import org.gstreamer.lowlevel.GstNative; import org.gstreamer.lowlevel.GstParseAPI; import org.gstreamer.lowlevel.GstPipelineAPI; import org.gstreamer.lowlevel.GstQueryAPI; import org.gstreamer.lowlevel.annotations.CallerOwnsReturn; import com.sun.jna.Pointer; /** * A {@code Pipeline} is a special {@link Bin} used as the toplevel container for * the filter graph. The <tt>Pipeline</tt> will manage the selection and * distribution of a global {@link Clock} as well as provide a {@link Bus} to * the application. It will also implement a default behavour for managing * seek events (see {@link #seek seek}). * * <p> * Elements are added and removed from the pipeline using the {@code Bin} * methods like {@link Bin#add add} and {@link Bin#remove remove}. * * <p> * Before changing the state of the <tt>Pipeline</tt> (see {@link Element}) a * {@link Bus} can be retrieved with {@link #getBus getBus}. This bus can then * be used to receive {@link Message}s from the elements in the pipeline. * * <p> * By default, a <tt>Pipeline</tt> will automatically flush the pending <tt>Bus</tt> * messages when going to the NULL state to ensure that no circular * references exist when no messages are read from the <tt>Bus</tt>. This * behaviour can be changed with {@link #setAutoFlushBus setAutoFlushBus} * * <p> * When the <tt>Pipeline</tt> performs the PAUSED to PLAYING state change it will * select a clock for the elements. The clock selection algorithm will by * default select a clock provided by an element that is most upstream * (closest to the source). For live pipelines (ones that return * {@link StateChangeReturn#NO_PREROLL} from the * {@link Element#setState setState} call) this will select the clock provided * by the live source. For normal pipelines this will select a clock provided * by the sinks (most likely the audio sink). If no element provides a clock, * a default <tt>SystemClock</tt> is used. * * <p> * The clock selection can be controlled with the gst_pipeline_use_clock() * method, which will enforce a given clock on the pipeline. With * gst_pipeline_auto_clock() the default clock selection algorithm can be * restored. * * <p> * A <tt>Pipeline</tt> maintains a stream time for the elements. The stream * time is defined as the difference between the current clock time and * the base time. When the pipeline goes to READY or a flushing seek is * performed on it, the stream time is reset to 0. When the pipeline is * set from PLAYING to PAUSED, the current clock time is sampled and used to * configure the base time for the elements when the pipeline is set * to PLAYING again. This default behaviour can be changed with the * gst_pipeline_set_new_stream_time() method. * * When sending a flushing seek event to a GstPipeline (see * {@link #seek seek}), it will make sure that the pipeline is properly * PAUSED and resumed as well as set the new stream time to 0 when the * seek succeeded. */ public class Pipeline extends Bin { public static final String GST_NAME = "pipeline"; public static final String GTYPE_NAME = "GstPipeline"; private static interface API extends GstElementAPI, GstPipelineAPI, GstParseAPI { @CallerOwnsReturn Pointer ptr_gst_pipeline_new(String name); } private static final API gst = GstNative.load(API.class); public Pipeline(Initializer init) { super(init); } /** * Creates a new instance of Pipeline with a unique name. */ public Pipeline() { this(initializer(gst.ptr_gst_pipeline_new(null))); initBus(); } /** * Creates a new instance of Pipeline with the given name. * * @param name The name used to identify this pipeline. */ public Pipeline(String name) { this(initializer(gst.ptr_gst_pipeline_new(name))); initBus(); } /** * Creates a pipeline from a text pipeline description. * * This function allows creation of a pipeline based on the syntax used in the * gst-launch utillity. * * @param pipelineDecription the command line describing the pipeline * @return The new Pipeline. */ public static Pipeline launch(String pipelineDecription) { Pointer[] err = { null }; Pipeline pipeline = gst.gst_parse_launch(pipelineDecription, err); if (pipeline == null) { throw new GstException(new GError(new GErrorStruct(err[0]))); } pipeline.initBus(); return pipeline; } /** * Creates a pipeline from a text pipeline description. * * This function allows creation of a pipeline based on the syntax used in the * gst-launch utillity. * * @param pipelineDecription An array of strings containing the command line describing the pipeline. * @return The new Pipeline. */ public static Pipeline launch(String... pipelineDecription) { Pointer[] err = { null }; Pipeline pipeline = gst.gst_parse_launchv(pipelineDecription, err); if (pipeline == null) { throw new GstException(new GError(new GErrorStruct(err[0]))); } pipeline.initBus(); return pipeline; } private void initBus() { Bus bus = getBus(); // // This is mostly a hack to get the Bus to install a sync message handler // bus.setFlushing(true); bus.setFlushing(false); } /** * Sets this pipeline to automatically flush {@link Bus} messages or not. * * @param flush true if automatic flushing is desired, else false. */ public void setAutoFlushBus(boolean flush) { gst.gst_pipeline_set_auto_flush_bus(this, flush); } /** * Checks if the pipeline will automatically flush messages when going to the NULL state. * * @return true if the pipeline automatically flushes messages. */ public boolean getAutoFlushBus() { return gst.gst_pipeline_get_auto_flush_bus(this); } /** * Set the clock for pipeline. * The clock will be distributed to all the elements managed by the pipeline. * <p>MT safe * * @param clock The {@link Clock} to use * @return true if the clock could be set on the pipeline, false if some * element did not accept the clock. * */ public boolean setClock(Clock clock) { return gst.gst_pipeline_set_clock(this, clock); } /** * Return the current {@link Clock} used by the pipeline. * * @return The {@link Clock} currently in use. */ @Override public Clock getClock() { return gst.gst_pipeline_get_clock(this); } /** * Force the Pipeline to use the a specific clock. * The pipeline will always use the given clock even if new clock * providers are added to this pipeline. * <p>MT safe * * @param clock The {@link Clock} to use. If clock is null, all clocking is * disabled, and the pipeline will run as fast as possible. * */ public void useClock(Clock clock) { gst.gst_pipeline_use_clock(this, clock); } /** * Gets the {@link Bus} this pipeline uses for messages. * * @return The {@link Bus} that this pipeline uses. */ @Override public Bus getBus() { return gst.gst_pipeline_get_bus(this); } /** * Gets the {@link Segment} for the current media stream in terms of the specified {@link Format}. * * @return The information regarding the current {@code Segment}. */ public Segment querySegment() { return querySegment(Format.TIME); } /** * Gets the {@link Segment} for the current media stream in terms of the specified {@link Format}. * * @param format the {@code Format} to return the segment in. * @return The information regarding the current {@code Segment}. */ public Segment querySegment(Format format) { Query qry = GstQueryAPI.GSTQUERY_API.gst_query_new_segment(format); gst.gst_element_query(this, qry); double[] rate = { 0.0D }; Format[] fmt = { Format.UNDEFINED }; long[] start_value = { 0 }; long[] stop_value = { 0 }; GstQueryAPI.GSTQUERY_API.gst_query_parse_segment(qry, rate, fmt, start_value, stop_value); return new Segment(rate[0], fmt[0], start_value[0], stop_value[0]); } }