/*
* 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]);
}
}