Blame gst/playback/gstdecodebin3.c

Packit 971217
/* GStreamer
Packit 971217
 *
Packit 971217
 * Copyright (C) <2015> Centricular Ltd
Packit 971217
 *  @author: Edward Hervey <edward@centricular.com>
Packit 971217
 *  @author: Jan Schmidt <jan@centricular.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
#include <glib.h>
Packit 971217
#include <glib-object.h>
Packit 971217
#include <glib/gprintf.h>
Packit 971217
#include <gst/gst.h>
Packit 971217
#include <gst/pbutils/pbutils.h>
Packit 971217
Packit 971217
#include "gstplayback.h"
Packit 971217
#include "gstplay-enum.h"
Packit 971217
#include "gstrawcaps.h"
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:element-decodebin3
Packit 971217
 * @title: decodebin3
Packit 971217
 *
Packit 971217
 * #GstBin that auto-magically constructs a decoding pipeline using available
Packit 971217
 * decoders and demuxers via auto-plugging. The output is raw audio, video
Packit 971217
 * or subtitle streams.
Packit 971217
 *
Packit 971217
 * decodebin3 differs from the previous decodebin (decodebin2) in important ways:
Packit 971217
 *
Packit 971217
 * * supports publication and selection of stream information via
Packit 971217
 * GstStreamCollection messages and #GST_EVENT_SELECT_STREAM events.
Packit 971217
 *
Packit 971217
 * * dynamically switches stream connections internally, and
Packit 971217
 * reuses decoder elements when stream selections change, so that in
Packit 971217
 * the normal case it maintains 1 decoder of each type (video/audio/subtitle)
Packit 971217
 * and only creates new elements when streams change and an existing decoder
Packit 971217
 * is not capable of handling the new format.
Packit 971217
 *
Packit 971217
 * * supports multiple input pads for the parallel decoding of auxilliary streams
Packit 971217
 * not muxed with the primary stream.
Packit 971217
 *
Packit 971217
 * * does not handle network stream buffering. decodebin3 expects that network stream
Packit 971217
 * buffering is handled upstream, before data is passed to it.
Packit 971217
 *
Packit 971217
 * <emphasis>decodebin3 is still experimental API and a technology preview.
Packit 971217
 * Its behaviour and exposed API is subject to change.</emphasis>
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * Global design
Packit 971217
 *
Packit 971217
 * 1) From sink pad to elementary streams (GstParseBin)
Packit 971217
 *
Packit 971217
 * The input sink pads are fed to GstParseBin. GstParseBin will feed them
Packit 971217
 * through typefind. When the caps are detected (or changed) we recursively
Packit 971217
 * figure out which demuxer, parser or depayloader is needed until we get to
Packit 971217
 * elementary streams.
Packit 971217
 *
Packit 971217
 * All elementary streams (whether decoded or not, whether exposed or not) are
Packit 971217
 * fed through multiqueue. There is only *one* multiqueue in decodebin3.
Packit 971217
 *
Packit 971217
 * => MultiQueue is the cornerstone.
Packit 971217
 * => No buffering before multiqueue
Packit 971217
 *
Packit 971217
 * 2) Elementary streams
Packit 971217
 *
Packit 971217
 * After GstParseBin, there are 3 main components:
Packit 971217
 *  1) Input Streams (provided by GstParseBin)
Packit 971217
 *  2) Multiqueue slots
Packit 971217
 *  3) Output Streams
Packit 971217
 *
Packit 971217
 * Input Streams correspond to the stream coming from GstParseBin and that gets
Packit 971217
 * fed into a multiqueue slot.
Packit 971217
 *
Packit 971217
 * Output Streams correspond to the combination of a (optional) decoder and an
Packit 971217
 * output ghostpad. Output Streams can be moved from one multiqueue slot to
Packit 971217
 * another, can reconfigure itself (different decoders), and can be
Packit 971217
 * added/removed depending on the configuration (all streams outputted, only one
Packit 971217
 * of each type, ...).
Packit 971217
 *
Packit 971217
 * Multiqueue slots correspond to a pair of sink/src pad from multiqueue. For
Packit 971217
 * each 'active' Input Stream there is a corresponding slot.
Packit 971217
 * Slots might have different streams on input and output (due to internal
Packit 971217
 * buffering).
Packit 971217
 *
Packit 971217
 * Due to internal queuing/buffering/..., all those components (might) behave
Packit 971217
 * asynchronously. Therefore probes will be used on each component source pad to
Packit 971217
 * detect various key-points:
Packit 971217
 *  * EOS :
Packit 971217
 *     the stream is done => Mark that component as done, optionally freeing/removing it
Packit 971217
 *  * STREAM_START :
Packit 971217
 *     a new stream is starting => link it further if needed
Packit 971217
 *
Packit 971217
 * 3) Gradual replacement
Packit 971217
 *
Packit 971217
 * If the caps change at any point in decodebin (input sink pad, demuxer output,
Packit 971217
 * multiqueue output, ..), we gradually replace (if needed) the following elements.
Packit 971217
 *
Packit 971217
 * This is handled by the probes in various locations:
Packit 971217
 *  a) typefind output
Packit 971217
 *  b) multiqueue input (source pad of Input Streams)
Packit 971217
 *  c) multiqueue output (source pad of Multiqueue Slots)
Packit 971217
 *  d) final output (target of source ghostpads)
Packit 971217
 *
Packit 971217
 * When CAPS event arrive at those points, one of three things can happen:
Packit 971217
 * a) There is no elements downstream yet, just create/link-to following elements
Packit 971217
 * b) There are downstream elements, do a ACCEPT_CAPS query
Packit 971217
 *  b.1) The new CAPS are accepted, keep current configuration
Packit 971217
 *  b.2) The new CAPS are not accepted, remove following elements then do a)
Packit 971217
 *
Packit 971217
 *    Components:
Packit 971217
 *
Packit 971217
 *                                                   MultiQ     Output
Packit 971217
 *                     Input(s)                      Slots      Streams
Packit 971217
 *  /-------------------------------------------\   /-----\  /------------- \
Packit 971217
 *
Packit 971217
 * +-------------------------------------------------------------------------+
Packit 971217
 * |                                                                         |
Packit 971217
 * | +---------------------------------------------+                         |
Packit 971217
 * | |   GstParseBin(s)                            |                         |
Packit 971217
 * | |                +--------------+             |  +-----+                |
Packit 971217
 * | |                |              |---[parser]-[|--| Mul |---[ decoder ]-[|
Packit 971217
 * |]--[ typefind ]---|  demuxer(s)  |------------[|  | ti  |                |
Packit 971217
 * | |                |  (if needed) |---[parser]-[|--| qu  |                |
Packit 971217
 * | |                |              |---[parser]-[|--| eu  |---[ decoder ]-[|
Packit 971217
 * | |                +--------------+             |  +------             ^  |
Packit 971217
 * | +---------------------------------------------+        ^             |  |
Packit 971217
 * |                                               ^        |             |  |
Packit 971217
 * +-----------------------------------------------+--------+-------------+--+
Packit 971217
 *                                                 |        |             |
Packit 971217
 *                                                 |        |             |
Packit 971217
 *                                       Probes  --/--------/-------------/
Packit 971217
 *
Packit 971217
 * ATOMIC SWITCHING
Packit 971217
 *
Packit 971217
 * We want to ensure we re-use decoders when switching streams. This takes place
Packit 971217
 * at the multiqueue output level.
Packit 971217
 *
Packit 971217
 * MAIN CONCEPTS
Packit 971217
 *  1) Activating a stream (i.e. linking a slot to an output) is only done within
Packit 971217
 *    the streaming thread in the multiqueue_src_probe() and only if the
Packit 971217
      stream is in the REQUESTED selection.
Packit 971217
 *  2) Deactivating a stream (i.e. unlinking a slot from an output) is also done
Packit 971217
 *    within the stream thread, but only in a purposefully called IDLE probe
Packit 971217
 *    that calls reassign_slot().
Packit 971217
 *
Packit 971217
 * Based on those two principles, 3 "selection" of streams (stream-id) are used:
Packit 971217
 * 1) requested_selection
Packit 971217
 *    All streams within that list should be activated
Packit 971217
 * 2) active_selection
Packit 971217
 *    List of streams that are exposed by decodebin
Packit 971217
 * 3) to_activate
Packit 971217
 *    List of streams that will be moved to requested_selection in the
Packit 971217
 *    reassign_slot() method (i.e. once a stream was deactivated, and the output
Packit 971217
 *    was retargetted)
Packit 971217
 */
Packit 971217
Packit 971217
Packit 971217
GST_DEBUG_CATEGORY_STATIC (decodebin3_debug);
Packit 971217
#define GST_CAT_DEFAULT decodebin3_debug
Packit 971217
Packit 971217
#define GST_TYPE_DECODEBIN3	 (gst_decodebin3_get_type ())
Packit 971217
Packit 971217
#define EXTRA_DEBUG 1
Packit 971217
Packit 971217
#define CUSTOM_FINAL_EOS_QUARK _custom_final_eos_quark_get ()
Packit 971217
#define CUSTOM_FINAL_EOS_QUARK_DATA "custom-final-eos"
Packit 971217
static GQuark
Packit 971217
_custom_final_eos_quark_get (void)
Packit 971217
{
Packit 971217
  static gsize g_quark;
Packit 971217
Packit 971217
  if (g_once_init_enter (&g_quark)) {
Packit 971217
    gsize quark =
Packit 971217
        (gsize) g_quark_from_static_string ("decodebin3-custom-final-eos");
Packit 971217
    g_once_init_leave (&g_quark, quark);
Packit 971217
  }
Packit 971217
  return g_quark;
Packit 971217
}
Packit 971217
Packit 971217
typedef struct _GstDecodebin3 GstDecodebin3;
Packit 971217
typedef struct _GstDecodebin3Class GstDecodebin3Class;
Packit 971217
Packit 971217
typedef struct _DecodebinInputStream DecodebinInputStream;
Packit 971217
typedef struct _DecodebinInput DecodebinInput;
Packit 971217
typedef struct _DecodebinOutputStream DecodebinOutputStream;
Packit 971217
Packit 971217
struct _GstDecodebin3
Packit 971217
{
Packit 971217
  GstBin bin;
Packit 971217
Packit 971217
  /* input_lock protects the following variables */
Packit 971217
  GMutex input_lock;
Packit 971217
  /* Main input (static sink pad) */
Packit 971217
  DecodebinInput *main_input;
Packit 971217
  /* Supplementary input (request sink pads) */
Packit 971217
  GList *other_inputs;
Packit 971217
  /* counter for input */
Packit 971217
  guint32 input_counter;
Packit 971217
  /* Current stream group_id (default : GST_GROUP_ID_INVALID) */
Packit 971217
  /* FIXME : Needs to be resetted appropriately (when upstream changes ?) */
Packit 971217
  guint32 current_group_id;
Packit 971217
  /* End of variables protected by input_lock */
Packit 971217
Packit 971217
  GstElement *multiqueue;
Packit 971217
Packit 971217
  /* selection_lock protects access to following variables */
Packit 971217
  GMutex selection_lock;
Packit 971217
  GList *input_streams;         /* List of DecodebinInputStream for active collection */
Packit 971217
  GList *output_streams;        /* List of DecodebinOutputStream used for output */
Packit 971217
  GList *slots;                 /* List of MultiQueueSlot */
Packit 971217
  guint slot_id;
Packit 971217
Packit 971217
  /* Active collection */
Packit 971217
  GstStreamCollection *collection;
Packit 971217
  /* requested selection of stream-id to activate post-multiqueue */
Packit 971217
  GList *requested_selection;
Packit 971217
  /* list of stream-id currently activated in output */
Packit 971217
  GList *active_selection;
Packit 971217
  /* List of stream-id that need to be activated (after a stream switch for ex) */
Packit 971217
  GList *to_activate;
Packit 971217
  /* Pending select streams event */
Packit 971217
  guint32 select_streams_seqnum;
Packit 971217
  /* pending list of streams to select (from downstream) */
Packit 971217
  GList *pending_select_streams;
Packit 971217
  /* TRUE if requested_selection was updated, will become FALSE once
Packit 971217
   * it has fully transitioned to active */
Packit 971217
  gboolean selection_updated;
Packit 971217
  /* End of variables protected by selection_lock */
Packit 971217
Packit 971217
  /* List of pending collections.
Packit 971217
   * FIXME : Is this really needed ? */
Packit 971217
  GList *pending_collection;
Packit 971217
Packit 971217
  /* Factories */
Packit 971217
  GMutex factories_lock;
Packit 971217
  guint32 factories_cookie;
Packit 971217
  /* All DECODABLE factories */
Packit 971217
  GList *factories;
Packit 971217
  /* Only DECODER factories */
Packit 971217
  GList *decoder_factories;
Packit 971217
  /* DECODABLE but not DECODER factories */
Packit 971217
  GList *decodable_factories;
Packit 971217
Packit 971217
  /* counters for pads */
Packit 971217
  guint32 apadcount, vpadcount, tpadcount, opadcount;
Packit 971217
Packit 971217
  /* Properties */
Packit 971217
  GstCaps *caps;
Packit 971217
};
Packit 971217
Packit 971217
struct _GstDecodebin3Class
Packit 971217
{
Packit 971217
  GstBinClass class;
Packit 971217
Packit 971217
    gint (*select_stream) (GstDecodebin3 * dbin,
Packit 971217
      GstStreamCollection * collection, GstStream * stream);
Packit 971217
};
Packit 971217
Packit 971217
/* Input of decodebin, controls input pad and parsebin */
Packit 971217
struct _DecodebinInput
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin;
Packit 971217
Packit 971217
  gboolean is_main;
Packit 971217
Packit 971217
  GstPad *ghost_sink;
Packit 971217
  GstPad *parsebin_sink;
Packit 971217
Packit 971217
  GstStreamCollection *collection;      /* Active collection */
Packit 971217
Packit 971217
  guint group_id;
Packit 971217
Packit 971217
  GstElement *parsebin;
Packit 971217
Packit 971217
  gulong pad_added_sigid;
Packit 971217
  gulong pad_removed_sigid;
Packit 971217
  gulong drained_sigid;
Packit 971217
Packit 971217
  /* TRUE if the input got drained
Packit 971217
   * FIXME : When do we reset it if re-used ?
Packit 971217
   */
Packit 971217
  gboolean drained;
Packit 971217
Packit 971217
  /* HACK : Remove these fields */
Packit 971217
  /* List of PendingPad structures */
Packit 971217
  GList *pending_pads;
Packit 971217
};
Packit 971217
Packit 971217
/* Multiqueue Slots */
Packit 971217
typedef struct _MultiQueueSlot
Packit 971217
{
Packit 971217
  guint id;
Packit 971217
Packit 971217
  GstDecodebin3 *dbin;
Packit 971217
  /* Type of stream handled by this slot */
Packit 971217
  GstStreamType type;
Packit 971217
Packit 971217
  /* Linked input and output */
Packit 971217
  DecodebinInputStream *input;
Packit 971217
Packit 971217
  /* pending => last stream received on sink pad */
Packit 971217
  GstStream *pending_stream;
Packit 971217
  /* active => last stream outputted on source pad */
Packit 971217
  GstStream *active_stream;
Packit 971217
Packit 971217
  GstPad *sink_pad, *src_pad;
Packit 971217
Packit 971217
  /* id of the MQ src_pad event probe */
Packit 971217
  gulong probe_id;
Packit 971217
Packit 971217
  gboolean is_drained;
Packit 971217
Packit 971217
  DecodebinOutputStream *output;
Packit 971217
} MultiQueueSlot;
Packit 971217
Packit 971217
/* Streams that are exposed downstream (i.e. output) */
Packit 971217
struct _DecodebinOutputStream
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin;
Packit 971217
  /* The type of stream handled by this output stream */
Packit 971217
  GstStreamType type;
Packit 971217
Packit 971217
  /* The slot to which this output stream is currently connected to */
Packit 971217
  MultiQueueSlot *slot;
Packit 971217
Packit 971217
  GstElement *decoder;          /* Optional */
Packit 971217
  GstPad *decoder_sink, *decoder_src;
Packit 971217
  gboolean linked;
Packit 971217
Packit 971217
  /* ghostpad */
Packit 971217
  GstPad *src_pad;
Packit 971217
  /* Flag if ghost pad is exposed */
Packit 971217
  gboolean src_exposed;
Packit 971217
Packit 971217
  /* keyframe dropping probe */
Packit 971217
  gulong drop_probe_id;
Packit 971217
};
Packit 971217
Packit 971217
/* Pending pads from parsebin */
Packit 971217
typedef struct _PendingPad
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin;
Packit 971217
  DecodebinInput *input;
Packit 971217
  GstPad *pad;
Packit 971217
Packit 971217
  gulong buffer_probe;
Packit 971217
  gulong event_probe;
Packit 971217
  gboolean saw_eos;
Packit 971217
} PendingPad;
Packit 971217
Packit 971217
/* properties */
Packit 971217
enum
Packit 971217
{
Packit 971217
  PROP_0,
Packit 971217
  PROP_CAPS
Packit 971217
};
Packit 971217
Packit 971217
/* signals */
Packit 971217
enum
Packit 971217
{
Packit 971217
  SIGNAL_SELECT_STREAM,
Packit 971217
  SIGNAL_ABOUT_TO_FINISH,
Packit 971217
  LAST_SIGNAL
Packit 971217
};
Packit 971217
static guint gst_decodebin3_signals[LAST_SIGNAL] = { 0 };
Packit 971217
Packit 971217
#define SELECTION_LOCK(dbin) G_STMT_START {				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "selection locking from thread %p",			\
Packit 971217
		    g_thread_self ());					\
Packit 971217
    g_mutex_lock (&dbin->selection_lock);				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "selection locked from thread %p",			\
Packit 971217
		    g_thread_self ());					\
Packit 971217
  } G_STMT_END
Packit 971217
Packit 971217
#define SELECTION_UNLOCK(dbin) G_STMT_START {				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "selection unlocking from thread %p",		\
Packit 971217
		    g_thread_self ());					\
Packit 971217
    g_mutex_unlock (&dbin->selection_lock);				\
Packit 971217
  } G_STMT_END
Packit 971217
Packit 971217
#define INPUT_LOCK(dbin) G_STMT_START {				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "input locking from thread %p",			\
Packit 971217
		    g_thread_self ());					\
Packit 971217
    g_mutex_lock (&dbin->input_lock);				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "input locked from thread %p",			\
Packit 971217
		    g_thread_self ());					\
Packit 971217
  } G_STMT_END
Packit 971217
Packit 971217
#define INPUT_UNLOCK(dbin) G_STMT_START {				\
Packit 971217
    GST_LOG_OBJECT (dbin,						\
Packit 971217
		    "input unlocking from thread %p",		\
Packit 971217
		    g_thread_self ());					\
Packit 971217
    g_mutex_unlock (&dbin->input_lock);				\
Packit 971217
  } G_STMT_END
Packit 971217
Packit 971217
GType gst_decodebin3_get_type (void);
Packit 971217
#define gst_decodebin3_parent_class parent_class
Packit 971217
G_DEFINE_TYPE (GstDecodebin3, gst_decodebin3, GST_TYPE_BIN);
Packit 971217
Packit 971217
static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
Packit 971217
Packit 971217
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate request_sink_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("sink_%u",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_REQUEST,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate video_src_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("video_%u",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_SOMETIMES,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate audio_src_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("audio_%u",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_SOMETIMES,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate text_src_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("text_%u",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_SOMETIMES,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
Packit 971217
    GST_PAD_SRC,
Packit 971217
    GST_PAD_SOMETIMES,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
Packit 971217
static void gst_decodebin3_dispose (GObject * object);
Packit 971217
static void gst_decodebin3_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_decodebin3_get_property (GObject * object, guint prop_id,
Packit 971217
    GValue * value, GParamSpec * pspec);
Packit 971217
Packit 971217
static gboolean parsebin_autoplug_continue_cb (GstElement *
Packit 971217
    parsebin, GstPad * pad, GstCaps * caps, GstDecodebin3 * dbin);
Packit 971217
Packit 971217
static gint
Packit 971217
gst_decodebin3_select_stream (GstDecodebin3 * dbin,
Packit 971217
    GstStreamCollection * collection, GstStream * stream)
Packit 971217
{
Packit 971217
  GST_LOG_OBJECT (dbin, "default select-stream, returning -1");
Packit 971217
Packit 971217
  return -1;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *gst_decodebin3_request_new_pad (GstElement * element,
Packit 971217
    GstPadTemplate * temp, const gchar * name, const GstCaps * caps);
Packit 971217
static void gst_decodebin3_handle_message (GstBin * bin, GstMessage * message);
Packit 971217
static GstStateChangeReturn gst_decodebin3_change_state (GstElement * element,
Packit 971217
    GstStateChange transition);
Packit 971217
static gboolean gst_decodebin3_send_event (GstElement * element,
Packit 971217
    GstEvent * event);
Packit 971217
Packit 971217
static void gst_decode_bin_update_factories_list (GstDecodebin3 * dbin);
Packit 971217
#if 0
Packit 971217
static gboolean have_factory (GstDecodebin3 * dbin, GstCaps * caps,
Packit 971217
    GstElementFactoryListType ftype);
Packit 971217
#endif
Packit 971217
Packit 971217
static void free_input (GstDecodebin3 * dbin, DecodebinInput * input);
Packit 971217
static void free_input_async (GstDecodebin3 * dbin, DecodebinInput * input);
Packit 971217
static DecodebinInput *create_new_input (GstDecodebin3 * dbin, gboolean main);
Packit 971217
static gboolean set_input_group_id (DecodebinInput * input, guint32 * group_id);
Packit 971217
Packit 971217
static void reconfigure_output_stream (DecodebinOutputStream * output,
Packit 971217
    MultiQueueSlot * slot);
Packit 971217
static void free_output_stream (GstDecodebin3 * dbin,
Packit 971217
    DecodebinOutputStream * output);
Packit 971217
static DecodebinOutputStream *create_output_stream (GstDecodebin3 * dbin,
Packit 971217
    GstStreamType type);
Packit 971217
Packit 971217
static GstPadProbeReturn slot_unassign_probe (GstPad * pad,
Packit 971217
    GstPadProbeInfo * info, MultiQueueSlot * slot);
Packit 971217
static gboolean reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot);
Packit 971217
static MultiQueueSlot *get_slot_for_input (GstDecodebin3 * dbin,
Packit 971217
    DecodebinInputStream * input);
Packit 971217
static void link_input_to_slot (DecodebinInputStream * input,
Packit 971217
    MultiQueueSlot * slot);
Packit 971217
static void free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot);
Packit 971217
static void free_multiqueue_slot_async (GstDecodebin3 * dbin,
Packit 971217
    MultiQueueSlot * slot);
Packit 971217
Packit 971217
static GstStreamCollection *get_merged_collection (GstDecodebin3 * dbin);
Packit 971217
static void update_requested_selection (GstDecodebin3 * dbin);
Packit 971217
Packit 971217
/* FIXME: Really make all the parser stuff a self-contained helper object */
Packit 971217
#include "gstdecodebin3-parse.c"
Packit 971217
Packit 971217
static gboolean
Packit 971217
_gst_int_accumulator (GSignalInvocationHint * ihint,
Packit 971217
    GValue * return_accu, const GValue * handler_return, gpointer dummy)
Packit 971217
{
Packit 971217
  gint res = g_value_get_int (handler_return);
Packit 971217
Packit 971217
  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
Packit 971217
    g_value_set_int (return_accu, res);
Packit 971217
Packit 971217
  if (res == -1)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_class_init (GstDecodebin3Class * klass)
Packit 971217
{
Packit 971217
  GObjectClass *gobject_klass = (GObjectClass *) klass;
Packit 971217
  GstElementClass *element_class = (GstElementClass *) klass;
Packit 971217
  GstBinClass *bin_klass = (GstBinClass *) klass;
Packit 971217
Packit 971217
  gobject_klass->dispose = gst_decodebin3_dispose;
Packit 971217
  gobject_klass->set_property = gst_decodebin3_set_property;
Packit 971217
  gobject_klass->get_property = gst_decodebin3_get_property;
Packit 971217
Packit 971217
  /* FIXME : ADD PROPERTIES ! */
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_CAPS,
Packit 971217
      g_param_spec_boxed ("caps", "Caps",
Packit 971217
          "The caps on which to stop decoding. (NULL = default)",
Packit 971217
          GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  /* FIXME : ADD SIGNALS ! */
Packit 971217
  /**
Packit 971217
   * GstDecodebin3::select-stream
Packit 971217
   * @decodebin: a #GstDecodebin3
Packit 971217
   * @collection: a #GstStreamCollection
Packit 971217
   * @stream: a #GstStream
Packit 971217
   *
Packit 971217
   * This signal is emitted whenever @decodebin needs to decide whether
Packit 971217
   * to expose a @stream of a given @collection.
Packit 971217
   *
Packit 971217
   * Returns: 1 if the stream should be selected, 0 if it shouldn't be selected.
Packit 971217
   * A value of -1 (default) lets @decodebin decide what to do with the stream.
Packit 971217
   * */
Packit 971217
  gst_decodebin3_signals[SIGNAL_SELECT_STREAM] =
Packit 971217
      g_signal_new ("select-stream", G_TYPE_FROM_CLASS (klass),
Packit 971217
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodebin3Class, select_stream),
Packit 971217
      _gst_int_accumulator, NULL, g_cclosure_marshal_generic,
Packit 971217
      G_TYPE_INT, 2, GST_TYPE_STREAM_COLLECTION, GST_TYPE_STREAM);
Packit 971217
Packit 971217
  /**
Packit 971217
   * GstDecodebin3::about-to-finish:
Packit 971217
   *
Packit 971217
   * This signal is emitted when the data for the selected URI is
Packit 971217
   * entirely buffered and it is safe to specify anothe URI.
Packit 971217
   */
Packit 971217
  gst_decodebin3_signals[SIGNAL_ABOUT_TO_FINISH] =
Packit 971217
      g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
Packit 971217
      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
Packit 971217
      0, G_TYPE_NONE);
Packit 971217
Packit 971217
Packit 971217
  element_class->request_new_pad =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_decodebin3_request_new_pad);
Packit 971217
  element_class->change_state = GST_DEBUG_FUNCPTR (gst_decodebin3_change_state);
Packit 971217
  element_class->send_event = GST_DEBUG_FUNCPTR (gst_decodebin3_send_event);
Packit 971217
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&sink_template));
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&request_sink_template));
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&video_src_template));
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&audio_src_template));
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&text_src_template));
Packit 971217
  gst_element_class_add_pad_template (element_class,
Packit 971217
      gst_static_pad_template_get (&src_template));
Packit 971217
Packit 971217
  gst_element_class_set_static_metadata (element_class,
Packit 971217
      "Decoder Bin 3", "Generic/Bin/Decoder",
Packit 971217
      "Autoplug and decode to raw media",
Packit 971217
      "Edward Hervey <edward@centricular.com>");
Packit 971217
Packit 971217
  bin_klass->handle_message = gst_decodebin3_handle_message;
Packit 971217
Packit 971217
  klass->select_stream = gst_decodebin3_select_stream;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_init (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  /* Create main input */
Packit 971217
  dbin->main_input = create_new_input (dbin, TRUE);
Packit 971217
Packit 971217
  dbin->multiqueue = gst_element_factory_make ("multiqueue", NULL);
Packit 971217
  g_object_set (dbin->multiqueue, "sync-by-running-time", TRUE,
Packit 971217
      "max-size-buffers", 0, "use-interleave", TRUE, NULL);
Packit 971217
  gst_bin_add ((GstBin *) dbin, dbin->multiqueue);
Packit 971217
Packit 971217
  dbin->current_group_id = GST_GROUP_ID_INVALID;
Packit 971217
Packit 971217
  g_mutex_init (&dbin->factories_lock);
Packit 971217
  g_mutex_init (&dbin->selection_lock);
Packit 971217
  g_mutex_init (&dbin->input_lock);
Packit 971217
Packit 971217
  dbin->caps = gst_static_caps_get (&default_raw_caps);
Packit 971217
Packit 971217
  GST_OBJECT_FLAG_SET (dbin, GST_BIN_FLAG_STREAMS_AWARE);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_dispose (GObject * object)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) object;
Packit 971217
  GList *walk, *next;
Packit 971217
Packit 971217
  if (dbin->factories)
Packit 971217
    gst_plugin_feature_list_free (dbin->factories);
Packit 971217
  if (dbin->decoder_factories)
Packit 971217
    g_list_free (dbin->decoder_factories);
Packit 971217
  if (dbin->decodable_factories)
Packit 971217
    g_list_free (dbin->decodable_factories);
Packit 971217
  g_list_free_full (dbin->requested_selection, g_free);
Packit 971217
  g_list_free (dbin->active_selection);
Packit 971217
  g_list_free (dbin->to_activate);
Packit 971217
  g_list_free (dbin->pending_select_streams);
Packit 971217
  g_clear_object (&dbin->collection);
Packit 971217
Packit 971217
  free_input (dbin, dbin->main_input);
Packit 971217
Packit 971217
  for (walk = dbin->other_inputs; walk; walk = next) {
Packit 971217
    DecodebinInput *input = walk->data;
Packit 971217
Packit 971217
    next = g_list_next (walk);
Packit 971217
Packit 971217
    free_input (dbin, input);
Packit 971217
    dbin->other_inputs = g_list_delete_link (dbin->other_inputs, walk);
Packit 971217
  }
Packit 971217
Packit 971217
  G_OBJECT_CLASS (parent_class)->dispose (object);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) object;
Packit 971217
Packit 971217
  /* FIXME : IMPLEMENT */
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_CAPS:
Packit 971217
      GST_OBJECT_LOCK (dbin);
Packit 971217
      if (dbin->caps)
Packit 971217
        gst_caps_unref (dbin->caps);
Packit 971217
      dbin->caps = g_value_dup_boxed (value);
Packit 971217
      GST_OBJECT_UNLOCK (dbin);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_get_property (GObject * object, guint prop_id, GValue * value,
Packit 971217
    GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) object;
Packit 971217
Packit 971217
  /* FIXME : IMPLEMENT */
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_CAPS:
Packit 971217
      GST_OBJECT_LOCK (dbin);
Packit 971217
      g_value_set_boxed (value, dbin->caps);
Packit 971217
      GST_OBJECT_UNLOCK (dbin);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
parsebin_autoplug_continue_cb (GstElement * parsebin, GstPad * pad,
Packit 971217
    GstCaps * caps, GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
Packit 971217
Packit 971217
  /* If it matches our target caps, expose it */
Packit 971217
  if (gst_caps_can_intersect (caps, dbin->caps))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/* This method should be called whenever a STREAM_START event
Packit 971217
 * comes out of a given parsebin.
Packit 971217
 * The caller shall replace the group_id if the function returns TRUE */
Packit 971217
static gboolean
Packit 971217
set_input_group_id (DecodebinInput * input, guint32 * group_id)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = input->dbin;
Packit 971217
Packit 971217
  if (input->group_id != *group_id) {
Packit 971217
    if (input->group_id != GST_GROUP_ID_INVALID)
Packit 971217
      GST_WARNING_OBJECT (dbin,
Packit 971217
          "Group id changed (%" G_GUINT32_FORMAT " -> %" G_GUINT32_FORMAT
Packit 971217
          ") on input %p ", input->group_id, *group_id, input);
Packit 971217
    input->group_id = *group_id;
Packit 971217
  }
Packit 971217
Packit 971217
  if (*group_id != dbin->current_group_id) {
Packit 971217
    if (dbin->current_group_id == GST_GROUP_ID_INVALID) {
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Setting current group id to %" G_GUINT32_FORMAT,
Packit 971217
          *group_id);
Packit 971217
      dbin->current_group_id = *group_id;
Packit 971217
    }
Packit 971217
    *group_id = dbin->current_group_id;
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
parsebin_drained_cb (GstElement * parsebin, DecodebinInput * input)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = input->dbin;
Packit 971217
  gboolean all_drained;
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  GST_WARNING_OBJECT (dbin, "input %p drained", input);
Packit 971217
  input->drained = TRUE;
Packit 971217
Packit 971217
  all_drained = dbin->main_input->drained;
Packit 971217
  for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
Packit 971217
    DecodebinInput *data = (DecodebinInput *) tmp->data;
Packit 971217
Packit 971217
    all_drained &= data->drained;
Packit 971217
  }
Packit 971217
Packit 971217
  if (all_drained) {
Packit 971217
    GST_WARNING_OBJECT (dbin, "All inputs drained. Posting about-to-finish");
Packit 971217
    g_signal_emit (dbin, gst_decodebin3_signals[SIGNAL_ABOUT_TO_FINISH], 0,
Packit 971217
        NULL);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* Call with INPUT_LOCK taken */
Packit 971217
static gboolean
Packit 971217
ensure_input_parsebin (GstDecodebin3 * dbin, DecodebinInput * input)
Packit 971217
{
Packit 971217
  gboolean set_state = FALSE;
Packit 971217
Packit 971217
  if (input->parsebin == NULL) {
Packit 971217
    input->parsebin = gst_element_factory_make ("parsebin", NULL);
Packit 971217
    if (input->parsebin == NULL)
Packit 971217
      goto no_parsebin;
Packit 971217
    input->parsebin = gst_object_ref (input->parsebin);
Packit 971217
    input->parsebin_sink = gst_element_get_static_pad (input->parsebin, "sink");
Packit 971217
    input->pad_added_sigid =
Packit 971217
        g_signal_connect (input->parsebin, "pad-added",
Packit 971217
        (GCallback) parsebin_pad_added_cb, input);
Packit 971217
    input->pad_removed_sigid =
Packit 971217
        g_signal_connect (input->parsebin, "pad-removed",
Packit 971217
        (GCallback) parsebin_pad_removed_cb, input);
Packit 971217
    input->drained_sigid =
Packit 971217
        g_signal_connect (input->parsebin, "drained",
Packit 971217
        (GCallback) parsebin_drained_cb, input);
Packit 971217
    g_signal_connect (input->parsebin, "autoplug-continue",
Packit 971217
        (GCallback) parsebin_autoplug_continue_cb, dbin);
Packit 971217
  }
Packit 971217
Packit 971217
  if (GST_OBJECT_PARENT (GST_OBJECT (input->parsebin)) != GST_OBJECT (dbin)) {
Packit 971217
    gst_bin_add (GST_BIN (dbin), input->parsebin);
Packit 971217
    set_state = TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_ghost_pad_set_target (GST_GHOST_PAD (input->ghost_sink),
Packit 971217
      input->parsebin_sink);
Packit 971217
  if (set_state)
Packit 971217
    gst_element_sync_state_with_parent (input->parsebin);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_parsebin:
Packit 971217
  {
Packit 971217
    gst_element_post_message ((GstElement *) dbin,
Packit 971217
        gst_missing_element_message_new ((GstElement *) dbin, "parsebin"));
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static GstPadLinkReturn
Packit 971217
gst_decodebin3_input_pad_link (GstPad * pad, GstObject * parent, GstPad * peer)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
Packit 971217
  GstPadLinkReturn res = GST_PAD_LINK_OK;
Packit 971217
  DecodebinInput *input;
Packit 971217
Packit 971217
  GST_LOG_OBJECT (parent, "Got link on input pad %" GST_PTR_FORMAT
Packit 971217
      ". Creating parsebin if needed", pad);
Packit 971217
Packit 971217
  if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
Packit 971217
    goto fail;
Packit 971217
Packit 971217
  INPUT_LOCK (dbin);
Packit 971217
  if (!ensure_input_parsebin (dbin, input))
Packit 971217
    res = GST_PAD_LINK_REFUSED;
Packit 971217
  INPUT_UNLOCK (dbin);
Packit 971217
Packit 971217
  return res;
Packit 971217
fail:
Packit 971217
  GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
Packit 971217
  return GST_PAD_LINK_REFUSED;
Packit 971217
}
Packit 971217
Packit 971217
/* Drop duration query during _input_pad_unlink */
Packit 971217
static GstPadProbeReturn
Packit 971217
query_duration_drop_probe (GstPad * pad, GstPadProbeInfo * info,
Packit 971217
    DecodebinInput * input)
Packit 971217
{
Packit 971217
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
Packit 971217
Packit 971217
  if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) {
Packit 971217
    GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
Packit 971217
    if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
Packit 971217
      GST_LOG_OBJECT (pad, "stop forwarding query duration");
Packit 971217
      ret = GST_PAD_PROBE_HANDLED;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_input_pad_unlink (GstPad * pad, GstObject * parent)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
Packit 971217
  DecodebinInput *input;
Packit 971217
Packit 971217
  GST_LOG_OBJECT (parent, "Got unlink on input pad %" GST_PTR_FORMAT
Packit 971217
      ". Removing parsebin.", pad);
Packit 971217
Packit 971217
  if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
Packit 971217
    goto fail;
Packit 971217
Packit 971217
  INPUT_LOCK (dbin);
Packit 971217
  if (input->parsebin == NULL) {
Packit 971217
    INPUT_UNLOCK (dbin);
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  if (GST_OBJECT_PARENT (GST_OBJECT (input->parsebin)) == GST_OBJECT (dbin)) {
Packit 971217
    GstStreamCollection *collection = NULL;
Packit 971217
    gulong probe_id = gst_pad_add_probe (input->parsebin_sink,
Packit 971217
        GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
Packit 971217
        (GstPadProbeCallback) query_duration_drop_probe, input, NULL);
Packit 971217
Packit 971217
    /* Clear stream-collection corresponding to current INPUT and post new
Packit 971217
     * stream-collection message, if needed */
Packit 971217
    if (input->collection) {
Packit 971217
      gst_object_unref (input->collection);
Packit 971217
      input->collection = NULL;
Packit 971217
    }
Packit 971217
Packit 971217
    SELECTION_LOCK (dbin);
Packit 971217
    collection = get_merged_collection (dbin);
Packit 971217
    if (collection && collection != dbin->collection) {
Packit 971217
      GstMessage *msg;
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Update Stream Collection");
Packit 971217
Packit 971217
      if (dbin->collection)
Packit 971217
        gst_object_unref (dbin->collection);
Packit 971217
      dbin->collection = collection;
Packit 971217
Packit 971217
      msg =
Packit 971217
          gst_message_new_stream_collection ((GstObject *) dbin,
Packit 971217
          dbin->collection);
Packit 971217
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
      gst_element_post_message (GST_ELEMENT_CAST (dbin), msg);
Packit 971217
      update_requested_selection (dbin);
Packit 971217
    } else
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
    gst_bin_remove (GST_BIN (dbin), input->parsebin);
Packit 971217
    gst_element_set_state (input->parsebin, GST_STATE_NULL);
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->pad_removed_sigid);
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->pad_added_sigid);
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->drained_sigid);
Packit 971217
    gst_pad_remove_probe (input->parsebin_sink, probe_id);
Packit 971217
    gst_object_unref (input->parsebin);
Packit 971217
    gst_object_unref (input->parsebin_sink);
Packit 971217
Packit 971217
    input->parsebin = NULL;
Packit 971217
    input->parsebin_sink = NULL;
Packit 971217
Packit 971217
    if (!input->is_main) {
Packit 971217
      dbin->other_inputs = g_list_remove (dbin->other_inputs, input);
Packit 971217
      free_input_async (dbin, input);
Packit 971217
    }
Packit 971217
  }
Packit 971217
  INPUT_UNLOCK (dbin);
Packit 971217
  return;
Packit 971217
Packit 971217
fail:
Packit 971217
  GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
Packit 971217
  return;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
free_input (GstDecodebin3 * dbin, DecodebinInput * input)
Packit 971217
{
Packit 971217
  GST_DEBUG ("Freeing input %p", input);
Packit 971217
  gst_ghost_pad_set_target (GST_GHOST_PAD (input->ghost_sink), NULL);
Packit 971217
  gst_element_remove_pad (GST_ELEMENT (dbin), input->ghost_sink);
Packit 971217
  if (input->parsebin) {
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->pad_removed_sigid);
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->pad_added_sigid);
Packit 971217
    g_signal_handler_disconnect (input->parsebin, input->drained_sigid);
Packit 971217
    gst_element_set_state (input->parsebin, GST_STATE_NULL);
Packit 971217
    gst_object_unref (input->parsebin);
Packit 971217
    gst_object_unref (input->parsebin_sink);
Packit 971217
  }
Packit 971217
  if (input->collection)
Packit 971217
    gst_object_unref (input->collection);
Packit 971217
  g_free (input);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
free_input_async (GstDecodebin3 * dbin, DecodebinInput * input)
Packit 971217
{
Packit 971217
  GST_LOG_OBJECT (dbin, "pushing input %p on thread pool to free", input);
Packit 971217
  gst_element_call_async (GST_ELEMENT_CAST (dbin),
Packit 971217
      (GstElementCallAsyncFunc) free_input, input, NULL);
Packit 971217
}
Packit 971217
Packit 971217
/* Call with INPUT_LOCK taken */
Packit 971217
static DecodebinInput *
Packit 971217
create_new_input (GstDecodebin3 * dbin, gboolean main)
Packit 971217
{
Packit 971217
  DecodebinInput *input;
Packit 971217
Packit 971217
  input = g_new0 (DecodebinInput, 1);
Packit 971217
  input->dbin = dbin;
Packit 971217
  input->is_main = main;
Packit 971217
  input->group_id = GST_GROUP_ID_INVALID;
Packit 971217
  if (main)
Packit 971217
    input->ghost_sink = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
Packit 971217
  else {
Packit 971217
    gchar *pad_name = g_strdup_printf ("sink_%u", dbin->input_counter++);
Packit 971217
    input->ghost_sink = gst_ghost_pad_new_no_target (pad_name, GST_PAD_SINK);
Packit 971217
    g_free (pad_name);
Packit 971217
  }
Packit 971217
  g_object_set_data (G_OBJECT (input->ghost_sink), "decodebin.input", input);
Packit 971217
  gst_pad_set_link_function (input->ghost_sink, gst_decodebin3_input_pad_link);
Packit 971217
  gst_pad_set_unlink_function (input->ghost_sink,
Packit 971217
      gst_decodebin3_input_pad_unlink);
Packit 971217
Packit 971217
  gst_pad_set_active (input->ghost_sink, TRUE);
Packit 971217
  gst_element_add_pad ((GstElement *) dbin, input->ghost_sink);
Packit 971217
Packit 971217
  return input;
Packit 971217
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
gst_decodebin3_request_new_pad (GstElement * element, GstPadTemplate * temp,
Packit 971217
    const gchar * name, const GstCaps * caps)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) element;
Packit 971217
  DecodebinInput *input;
Packit 971217
  GstPad *res = NULL;
Packit 971217
Packit 971217
  /* We are ignoring names for the time being, not sure it makes any sense
Packit 971217
   * within the context of decodebin3 ... */
Packit 971217
  input = create_new_input (dbin, FALSE);
Packit 971217
  if (input) {
Packit 971217
    INPUT_LOCK (dbin);
Packit 971217
    dbin->other_inputs = g_list_append (dbin->other_inputs, input);
Packit 971217
    res = input->ghost_sink;
Packit 971217
    INPUT_UNLOCK (dbin);
Packit 971217
  }
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/* Must be called with factories lock! */
Packit 971217
static void
Packit 971217
gst_decode_bin_update_factories_list (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  guint cookie;
Packit 971217
Packit 971217
  cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
Packit 971217
  if (!dbin->factories || dbin->factories_cookie != cookie) {
Packit 971217
    GList *tmp;
Packit 971217
    if (dbin->factories)
Packit 971217
      gst_plugin_feature_list_free (dbin->factories);
Packit 971217
    if (dbin->decoder_factories)
Packit 971217
      g_list_free (dbin->decoder_factories);
Packit 971217
    if (dbin->decodable_factories)
Packit 971217
      g_list_free (dbin->decodable_factories);
Packit 971217
    dbin->factories =
Packit 971217
        gst_element_factory_list_get_elements
Packit 971217
        (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
Packit 971217
    dbin->factories =
Packit 971217
        g_list_sort (dbin->factories, gst_plugin_feature_rank_compare_func);
Packit 971217
    dbin->factories_cookie = cookie;
Packit 971217
Packit 971217
    /* Filter decoder and other decodables */
Packit 971217
    dbin->decoder_factories = NULL;
Packit 971217
    dbin->decodable_factories = NULL;
Packit 971217
    for (tmp = dbin->factories; tmp; tmp = tmp->next) {
Packit 971217
      GstElementFactory *fact = (GstElementFactory *) tmp->data;
Packit 971217
      if (gst_element_factory_list_is_type (fact,
Packit 971217
              GST_ELEMENT_FACTORY_TYPE_DECODER))
Packit 971217
        dbin->decoder_factories = g_list_append (dbin->decoder_factories, fact);
Packit 971217
      else
Packit 971217
        dbin->decodable_factories =
Packit 971217
            g_list_append (dbin->decodable_factories, fact);
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* Must be called with appropriate lock if list is a protected variable */
Packit 971217
static const gchar *
Packit 971217
stream_in_list (GList * list, const gchar * sid)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
#if EXTRA_DEBUG
Packit 971217
  for (tmp = list; tmp; tmp = tmp->next) {
Packit 971217
    gchar *osid = (gchar *) tmp->data;
Packit 971217
    GST_DEBUG ("Checking %s against %s", sid, osid);
Packit 971217
  }
Packit 971217
#endif
Packit 971217
Packit 971217
  for (tmp = list; tmp; tmp = tmp->next) {
Packit 971217
    const gchar *osid = (gchar *) tmp->data;
Packit 971217
    if (!g_strcmp0 (sid, osid))
Packit 971217
      return osid;
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
update_requested_selection (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  guint i, nb;
Packit 971217
  GList *tmp = NULL;
Packit 971217
  GstStreamType used_types = 0;
Packit 971217
  GstStreamCollection *collection;
Packit 971217
Packit 971217
  /* 1. Is there a pending SELECT_STREAMS we can return straight away since
Packit 971217
   *  the switch handler will take care of the pending selection */
Packit 971217
  SELECTION_LOCK (dbin);
Packit 971217
  if (dbin->pending_select_streams) {
Packit 971217
    GST_DEBUG_OBJECT (dbin,
Packit 971217
        "No need to create pending selection, SELECT_STREAMS underway");
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  collection = dbin->collection;
Packit 971217
  if (G_UNLIKELY (collection == NULL)) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "No current GstStreamCollection");
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
  nb = gst_stream_collection_get_size (collection);
Packit 971217
Packit 971217
  /* 2. If not, are we in EXPOSE_ALL_MODE ? If so, match everything */
Packit 971217
  GST_FIXME_OBJECT (dbin, "Implement EXPOSE_ALL_MODE");
Packit 971217
Packit 971217
  /* 3. If not, check if we already have some of the streams in the
Packit 971217
   * existing active/requested selection */
Packit 971217
  for (i = 0; i < nb; i++) {
Packit 971217
    GstStream *stream = gst_stream_collection_get_stream (collection, i);
Packit 971217
    const gchar *sid = gst_stream_get_stream_id (stream);
Packit 971217
    gint request = -1;
Packit 971217
    /* Fire select-stream signal to see if outside components want to
Packit 971217
     * hint at which streams should be selected */
Packit 971217
    g_signal_emit (G_OBJECT (dbin),
Packit 971217
        gst_decodebin3_signals[SIGNAL_SELECT_STREAM], 0, collection, stream,
Packit 971217
        &request);
Packit 971217
    GST_DEBUG_OBJECT (dbin, "stream %s , request:%d", sid, request);
Packit 971217
    if (request == 1 || (request == -1
Packit 971217
            && (stream_in_list (dbin->requested_selection, sid)
Packit 971217
                || stream_in_list (dbin->active_selection, sid)))) {
Packit 971217
      GstStreamType curtype = gst_stream_get_stream_type (stream);
Packit 971217
      if (request == 1)
Packit 971217
        GST_DEBUG_OBJECT (dbin,
Packit 971217
            "Using stream requested by 'select-stream' signal : %s", sid);
Packit 971217
      else
Packit 971217
        GST_DEBUG_OBJECT (dbin,
Packit 971217
            "Re-using stream already present in requested or active selection : %s",
Packit 971217
            sid);
Packit 971217
      tmp = g_list_append (tmp, (gchar *) sid);
Packit 971217
      used_types |= curtype;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  /* 4. If not, match one stream of each type */
Packit 971217
  for (i = 0; i < nb; i++) {
Packit 971217
    GstStream *stream = gst_stream_collection_get_stream (collection, i);
Packit 971217
    GstStreamType curtype = gst_stream_get_stream_type (stream);
Packit 971217
    if (!(used_types & curtype)) {
Packit 971217
      const gchar *sid = gst_stream_get_stream_id (stream);
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Selecting stream '%s' of type %s",
Packit 971217
          sid, gst_stream_type_get_name (curtype));
Packit 971217
      tmp = g_list_append (tmp, (gchar *) sid);
Packit 971217
      used_types |= curtype;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
beach:
Packit 971217
  /* Finally set the requested selection */
Packit 971217
  if (tmp) {
Packit 971217
    if (dbin->requested_selection) {
Packit 971217
      GST_FIXME_OBJECT (dbin,
Packit 971217
          "Replacing non-NULL requested_selection, what should we do ??");
Packit 971217
      g_list_free_full (dbin->requested_selection, g_free);
Packit 971217
    }
Packit 971217
    dbin->requested_selection =
Packit 971217
        g_list_copy_deep (tmp, (GCopyFunc) g_strdup, NULL);
Packit 971217
    dbin->selection_updated = TRUE;
Packit 971217
    g_list_free (tmp);
Packit 971217
  }
Packit 971217
  SELECTION_UNLOCK (dbin);
Packit 971217
}
Packit 971217
Packit 971217
/* Call with INPUT_LOCK taken */
Packit 971217
static GstStreamCollection *
Packit 971217
get_merged_collection (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  gboolean needs_merge = FALSE;
Packit 971217
  GstStreamCollection *res = NULL;
Packit 971217
  GList *tmp;
Packit 971217
  guint i, nb_stream;
Packit 971217
Packit 971217
  /* First check if we need to do a merge or just return the only collection */
Packit 971217
  res = dbin->main_input->collection;
Packit 971217
Packit 971217
  for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
Packit 971217
    DecodebinInput *input = (DecodebinInput *) tmp->data;
Packit 971217
    if (input->collection) {
Packit 971217
      if (res) {
Packit 971217
        needs_merge = TRUE;
Packit 971217
        break;
Packit 971217
      }
Packit 971217
      res = input->collection;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (!needs_merge) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "No need to merge, returning %p", res);
Packit 971217
    return res ? gst_object_ref (res) : NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  /* We really need to create a new collection */
Packit 971217
  /* FIXME : Some numbering scheme maybe ?? */
Packit 971217
  res = gst_stream_collection_new ("decodebin3");
Packit 971217
  if (dbin->main_input->collection) {
Packit 971217
    nb_stream = gst_stream_collection_get_size (dbin->main_input->collection);
Packit 971217
    GST_DEBUG_OBJECT (dbin, "main input %p %d", dbin->main_input, nb_stream);
Packit 971217
    for (i = 0; i < nb_stream; i++) {
Packit 971217
      GstStream *stream =
Packit 971217
          gst_stream_collection_get_stream (dbin->main_input->collection, i);
Packit 971217
      gst_stream_collection_add_stream (res, gst_object_ref (stream));
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
Packit 971217
    DecodebinInput *input = (DecodebinInput *) tmp->data;
Packit 971217
    GST_DEBUG_OBJECT (dbin, "input %p , collection %p", input,
Packit 971217
        input->collection);
Packit 971217
    if (input->collection) {
Packit 971217
      nb_stream = gst_stream_collection_get_size (input->collection);
Packit 971217
      GST_DEBUG_OBJECT (dbin, "nb_stream : %d", nb_stream);
Packit 971217
      for (i = 0; i < nb_stream; i++) {
Packit 971217
        GstStream *stream =
Packit 971217
            gst_stream_collection_get_stream (input->collection, i);
Packit 971217
        gst_stream_collection_add_stream (res, gst_object_ref (stream));
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/* Call with INPUT_LOCK taken */
Packit 971217
static DecodebinInput *
Packit 971217
find_message_parsebin (GstDecodebin3 * dbin, GstElement * child)
Packit 971217
{
Packit 971217
  DecodebinInput *input = NULL;
Packit 971217
  GstElement *parent = gst_object_ref (child);
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  do {
Packit 971217
    GstElement *next_parent;
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (dbin, "parent %s",
Packit 971217
        parent ? GST_ELEMENT_NAME (parent) : "<NONE>");
Packit 971217
Packit 971217
    if (parent == dbin->main_input->parsebin) {
Packit 971217
      input = dbin->main_input;
Packit 971217
      break;
Packit 971217
    }
Packit 971217
    for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
Packit 971217
      DecodebinInput *cur = (DecodebinInput *) tmp->data;
Packit 971217
      if (parent == cur->parsebin) {
Packit 971217
        input = cur;
Packit 971217
        break;
Packit 971217
      }
Packit 971217
    }
Packit 971217
    next_parent = (GstElement *) gst_element_get_parent (parent);
Packit 971217
    gst_object_unref (parent);
Packit 971217
    parent = next_parent;
Packit 971217
Packit 971217
  } while (parent && parent != (GstElement *) dbin);
Packit 971217
Packit 971217
  if (parent)
Packit 971217
    gst_object_unref (parent);
Packit 971217
Packit 971217
  return input;
Packit 971217
}
Packit 971217
Packit 971217
static const gchar *
Packit 971217
stream_in_collection (GstDecodebin3 * dbin, gchar * sid)
Packit 971217
{
Packit 971217
  guint i, len;
Packit 971217
Packit 971217
  if (dbin->collection == NULL)
Packit 971217
    return NULL;
Packit 971217
  len = gst_stream_collection_get_size (dbin->collection);
Packit 971217
  for (i = 0; i < len; i++) {
Packit 971217
    GstStream *stream = gst_stream_collection_get_stream (dbin->collection, i);
Packit 971217
    const gchar *osid = gst_stream_get_stream_id (stream);
Packit 971217
    if (!g_strcmp0 (sid, osid))
Packit 971217
      return osid;
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/* Call with INPUT_LOCK taken */
Packit 971217
static void
Packit 971217
handle_stream_collection (GstDecodebin3 * dbin,
Packit 971217
    GstStreamCollection * collection, GstElement * child)
Packit 971217
{
Packit 971217
#ifndef GST_DISABLE_GST_DEBUG
Packit 971217
  const gchar *upstream_id;
Packit 971217
  guint i;
Packit 971217
#endif
Packit 971217
  DecodebinInput *input = find_message_parsebin (dbin, child);
Packit 971217
Packit 971217
  if (!input) {
Packit 971217
    GST_DEBUG_OBJECT (dbin,
Packit 971217
        "Couldn't find corresponding input, most likely shutting down");
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Replace collection in input */
Packit 971217
  if (input->collection)
Packit 971217
    gst_object_unref (input->collection);
Packit 971217
  input->collection = gst_object_ref (collection);
Packit 971217
  GST_DEBUG_OBJECT (dbin, "Setting collection %p on input %p", collection,
Packit 971217
      input);
Packit 971217
Packit 971217
  /* Merge collection if needed */
Packit 971217
  collection = get_merged_collection (dbin);
Packit 971217
Packit 971217
#ifndef GST_DISABLE_GST_DEBUG
Packit 971217
  /* Just some debugging */
Packit 971217
  upstream_id = gst_stream_collection_get_upstream_id (collection);
Packit 971217
  GST_DEBUG ("Received Stream Collection. Upstream_id : %s", upstream_id);
Packit 971217
  GST_DEBUG ("From input %p", input);
Packit 971217
  GST_DEBUG ("  %d streams", gst_stream_collection_get_size (collection));
Packit 971217
  for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
Packit 971217
    GstStream *stream = gst_stream_collection_get_stream (collection, i);
Packit 971217
    GstTagList *taglist;
Packit 971217
    GstCaps *caps;
Packit 971217
Packit 971217
    GST_DEBUG ("   Stream '%s'", gst_stream_get_stream_id (stream));
Packit 971217
    GST_DEBUG ("     type  : %s",
Packit 971217
        gst_stream_type_get_name (gst_stream_get_stream_type (stream)));
Packit 971217
    GST_DEBUG ("     flags : 0x%x", gst_stream_get_stream_flags (stream));
Packit 971217
    taglist = gst_stream_get_tags (stream);
Packit 971217
    GST_DEBUG ("     tags  : %" GST_PTR_FORMAT, taglist);
Packit 971217
    caps = gst_stream_get_caps (stream);
Packit 971217
    GST_DEBUG ("     caps  : %" GST_PTR_FORMAT, caps);
Packit 971217
    if (taglist)
Packit 971217
      gst_tag_list_unref (taglist);
Packit 971217
    if (caps)
Packit 971217
      gst_caps_unref (caps);
Packit 971217
  }
Packit 971217
#endif
Packit 971217
Packit 971217
  /* Store collection for later usage */
Packit 971217
  SELECTION_LOCK (dbin);
Packit 971217
  if (dbin->collection == NULL) {
Packit 971217
    dbin->collection = collection;
Packit 971217
  } else {
Packit 971217
    /* We need to check who emitted this collection (the owner).
Packit 971217
     * If we already had a collection from that user, this one is an update,
Packit 971217
     * that is to say that we need to figure out how we are going to re-use
Packit 971217
     * the streams/slot */
Packit 971217
    GST_FIXME_OBJECT (dbin, "New collection but already had one ...");
Packit 971217
    /* FIXME : When do we switch from pending collection to active collection ?
Packit 971217
     * When all streams from active collection are drained in multiqueue output ? */
Packit 971217
    gst_object_unref (dbin->collection);
Packit 971217
    dbin->collection = collection;
Packit 971217
    /* dbin->pending_collection = */
Packit 971217
    /*     g_list_append (dbin->pending_collection, collection); */
Packit 971217
  }
Packit 971217
  SELECTION_UNLOCK (dbin);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_decodebin3_handle_message (GstBin * bin, GstMessage * message)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) bin;
Packit 971217
  gboolean posting_collection = FALSE;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (bin, "Got Message %s", GST_MESSAGE_TYPE_NAME (message));
Packit 971217
Packit 971217
  switch (GST_MESSAGE_TYPE (message)) {
Packit 971217
    case GST_MESSAGE_STREAM_COLLECTION:
Packit 971217
    {
Packit 971217
      GstStreamCollection *collection = NULL;
Packit 971217
      gst_message_parse_stream_collection (message, &collection);
Packit 971217
      if (collection) {
Packit 971217
        INPUT_LOCK (dbin);
Packit 971217
        handle_stream_collection (dbin, collection,
Packit 971217
            (GstElement *) GST_MESSAGE_SRC (message));
Packit 971217
        posting_collection = TRUE;
Packit 971217
        INPUT_UNLOCK (dbin);
Packit 971217
      }
Packit 971217
Packit 971217
      SELECTION_LOCK (dbin);
Packit 971217
      if (dbin->collection && collection != dbin->collection) {
Packit 971217
        /* Replace collection message, we most likely aggregated it */
Packit 971217
        GstMessage *new_msg;
Packit 971217
        new_msg =
Packit 971217
            gst_message_new_stream_collection ((GstObject *) dbin,
Packit 971217
            dbin->collection);
Packit 971217
        gst_message_unref (message);
Packit 971217
        message = new_msg;
Packit 971217
      }
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
      if (collection)
Packit 971217
        gst_object_unref (collection);
Packit 971217
      break;
Packit 971217
    }
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  GST_BIN_CLASS (parent_class)->handle_message (bin, message);
Packit 971217
Packit 971217
  if (posting_collection) {
Packit 971217
    /* Figure out a selection for that collection */
Packit 971217
    update_requested_selection (dbin);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static DecodebinOutputStream *
Packit 971217
find_free_compatible_output (GstDecodebin3 * dbin, GstStream * stream)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
  GstStreamType stype = gst_stream_get_stream_type (stream);
Packit 971217
Packit 971217
  for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
Packit 971217
    DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
Packit 971217
    if (output->type == stype && output->slot && output->slot->active_stream) {
Packit 971217
      GstStream *tstream = output->slot->active_stream;
Packit 971217
      if (!stream_in_list (dbin->requested_selection,
Packit 971217
              (gchar *) gst_stream_get_stream_id (tstream))) {
Packit 971217
        return output;
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/* Give a certain slot, figure out if it should be linked to an
Packit 971217
 * output stream
Packit 971217
 * CALL WITH SELECTION LOCK TAKEN !*/
Packit 971217
static DecodebinOutputStream *
Packit 971217
get_output_for_slot (MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = slot->dbin;
Packit 971217
  DecodebinOutputStream *output = NULL;
Packit 971217
  const gchar *stream_id;
Packit 971217
  GstCaps *caps;
Packit 971217
  gchar *id_in_list = NULL;
Packit 971217
Packit 971217
  /* If we already have a configured output, just use it */
Packit 971217
  if (slot->output != NULL)
Packit 971217
    return slot->output;
Packit 971217
Packit 971217
  /*
Packit 971217
   * FIXME
Packit 971217
   *
Packit 971217
   * This method needs to be split into multiple parts
Packit 971217
   *
Packit 971217
   * 1) Figure out whether stream should be exposed or not
Packit 971217
   *   This is based on autoplug-continue, EXPOSE_ALL_MODE, or presence
Packit 971217
   *   in the default stream attribution
Packit 971217
   *
Packit 971217
   * 2) Figure out whether an output stream should be created, whether
Packit 971217
   *   we can re-use the output stream already linked to the slot, or
Packit 971217
   *   whether we need to get re-assigned another (currently used) output
Packit 971217
   *   stream.
Packit 971217
   */
Packit 971217
Packit 971217
  stream_id = gst_stream_get_stream_id (slot->active_stream);
Packit 971217
  caps = gst_stream_get_caps (slot->active_stream);
Packit 971217
  GST_DEBUG_OBJECT (dbin, "stream %s , %" GST_PTR_FORMAT, stream_id, caps);
Packit 971217
  gst_caps_unref (caps);
Packit 971217
Packit 971217
  /* 0. Emit autoplug-continue signal for pending caps ? */
Packit 971217
  GST_FIXME_OBJECT (dbin, "emit autoplug-continue");
Packit 971217
Packit 971217
  /* 1. if in EXPOSE_ALL_MODE, just accept */
Packit 971217
  GST_FIXME_OBJECT (dbin, "Handle EXPOSE_ALL_MODE");
Packit 971217
Packit 971217
#if 0
Packit 971217
  /* FIXME : The idea around this was to avoid activating a stream for
Packit 971217
   *     which we have no decoder. Unfortunately it is way too
Packit 971217
   *     expensive. Need to figure out a better solution */
Packit 971217
  /* 2. Is there a potential decoder (if one is required) */
Packit 971217
  if (!gst_caps_can_intersect (caps, dbin->caps)
Packit 971217
      && !have_factory (dbin, (GstCaps *) caps,
Packit 971217
          GST_ELEMENT_FACTORY_TYPE_DECODER)) {
Packit 971217
    GST_WARNING_OBJECT (dbin, "Don't have a decoder for %" GST_PTR_FORMAT,
Packit 971217
        caps);
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
    gst_element_post_message (GST_ELEMENT_CAST (dbin),
Packit 971217
        gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps));
Packit 971217
    SELECTION_LOCK (dbin);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
#endif
Packit 971217
Packit 971217
  /* 3. In default mode check if we should expose */
Packit 971217
  id_in_list = (gchar *) stream_in_list (dbin->requested_selection, stream_id);
Packit 971217
  if (id_in_list) {
Packit 971217
    /* Check if we can steal an existing output stream we could re-use.
Packit 971217
     * that is:
Packit 971217
     * * an output stream whose slot->stream is not in requested
Packit 971217
     * * and is of the same type as this stream
Packit 971217
     */
Packit 971217
    output = find_free_compatible_output (dbin, slot->active_stream);
Packit 971217
    if (output) {
Packit 971217
      /* Move this output from its current slot to this slot */
Packit 971217
      dbin->to_activate =
Packit 971217
          g_list_append (dbin->to_activate, (gchar *) stream_id);
Packit 971217
      dbin->requested_selection =
Packit 971217
          g_list_remove (dbin->requested_selection, id_in_list);
Packit 971217
      g_free (id_in_list);
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
      gst_pad_add_probe (output->slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
Packit 971217
          (GstPadProbeCallback) slot_unassign_probe, output->slot, NULL);
Packit 971217
      SELECTION_LOCK (dbin);
Packit 971217
      return NULL;
Packit 971217
    }
Packit 971217
Packit 971217
    output = create_output_stream (dbin, slot->type);
Packit 971217
    output->slot = slot;
Packit 971217
    GST_DEBUG ("Linking slot %p to new output %p", slot, output);
Packit 971217
    slot->output = output;
Packit 971217
    dbin->active_selection =
Packit 971217
        g_list_append (dbin->active_selection, (gchar *) stream_id);
Packit 971217
  } else
Packit 971217
    GST_DEBUG ("Not creating any output for slot %p", slot);
Packit 971217
Packit 971217
  return output;
Packit 971217
}
Packit 971217
Packit 971217
/* Returns SELECTED_STREAMS message if active_selection is equal to
Packit 971217
 * requested_selection, else NULL.
Packit 971217
 * Must be called with LOCK taken */
Packit 971217
static GstMessage *
Packit 971217
is_selection_done (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
  GstMessage *msg;
Packit 971217
Packit 971217
  if (!dbin->selection_updated)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  GST_LOG_OBJECT (dbin, "Checking");
Packit 971217
Packit 971217
  if (dbin->to_activate != NULL) {
Packit 971217
    GST_DEBUG ("Still have streams to activate");
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
  for (tmp = dbin->requested_selection; tmp; tmp = tmp->next) {
Packit 971217
    GST_DEBUG ("Checking requested stream %s", (gchar *) tmp->data);
Packit 971217
    if (!stream_in_list (dbin->active_selection, (gchar *) tmp->data)) {
Packit 971217
      GST_DEBUG ("Not in active selection, returning");
Packit 971217
      return NULL;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin, "Selection active, creating message");
Packit 971217
Packit 971217
  /* We are completely active */
Packit 971217
  msg = gst_message_new_streams_selected ((GstObject *) dbin, dbin->collection);
Packit 971217
  GST_MESSAGE_SEQNUM (msg) = dbin->select_streams_seqnum;
Packit 971217
  for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
Packit 971217
    DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
Packit 971217
    if (output->slot) {
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Adding stream %s",
Packit 971217
          gst_stream_get_stream_id (output->slot->active_stream));
Packit 971217
Packit 971217
      gst_message_streams_selected_add (msg, output->slot->active_stream);
Packit 971217
    } else
Packit 971217
      GST_WARNING_OBJECT (dbin, "No valid slot for output %p", output);
Packit 971217
  }
Packit 971217
  dbin->selection_updated = FALSE;
Packit 971217
  return msg;
Packit 971217
}
Packit 971217
Packit 971217
/* Must be called with SELECTION_LOCK taken */
Packit 971217
static void
Packit 971217
check_all_slot_for_eos (GstDecodebin3 * dbin)
Packit 971217
{
Packit 971217
  gboolean all_drained = TRUE;
Packit 971217
  GList *iter;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin, "check slot for eos");
Packit 971217
Packit 971217
  for (iter = dbin->slots; iter; iter = iter->next) {
Packit 971217
    MultiQueueSlot *slot = iter->data;
Packit 971217
Packit 971217
    if (!slot->output)
Packit 971217
      continue;
Packit 971217
Packit 971217
    if (slot->is_drained) {
Packit 971217
      GST_LOG_OBJECT (slot->sink_pad, "slot %p is drained", slot);
Packit 971217
      continue;
Packit 971217
    }
Packit 971217
Packit 971217
    all_drained = FALSE;
Packit 971217
    break;
Packit 971217
  }
Packit 971217
Packit 971217
  if (all_drained) {
Packit 971217
    INPUT_LOCK (dbin);
Packit 971217
    if (!pending_pads_are_eos (dbin->main_input))
Packit 971217
      all_drained = FALSE;
Packit 971217
Packit 971217
    if (all_drained) {
Packit 971217
      for (iter = dbin->other_inputs; iter; iter = iter->next) {
Packit 971217
        if (!pending_pads_are_eos ((DecodebinInput *) iter->data)) {
Packit 971217
          all_drained = FALSE;
Packit 971217
          break;
Packit 971217
        }
Packit 971217
      }
Packit 971217
    }
Packit 971217
    INPUT_UNLOCK (dbin);
Packit 971217
  }
Packit 971217
Packit 971217
  if (all_drained) {
Packit 971217
    GST_DEBUG_OBJECT (dbin,
Packit 971217
        "All active slots are drained, and no pending input, push EOS");
Packit 971217
Packit 971217
    for (iter = dbin->input_streams; iter; iter = iter->next) {
Packit 971217
      DecodebinInputStream *input = (DecodebinInputStream *) iter->data;
Packit 971217
      GstPad *peer = gst_pad_get_peer (input->srcpad);
Packit 971217
Packit 971217
      /* Send EOS to all slots */
Packit 971217
      if (peer) {
Packit 971217
        GstEvent *stream_start, *eos;
Packit 971217
Packit 971217
        stream_start =
Packit 971217
            gst_pad_get_sticky_event (input->srcpad, GST_EVENT_STREAM_START, 0);
Packit 971217
Packit 971217
        /* First forward a custom STREAM_START event to reset the EOS status (if any) */
Packit 971217
        if (stream_start) {
Packit 971217
          GstStructure *s;
Packit 971217
          GstEvent *custom_stream_start = gst_event_copy (stream_start);
Packit 971217
          gst_event_unref (stream_start);
Packit 971217
          s = (GstStructure *) gst_event_get_structure (custom_stream_start);
Packit 971217
          gst_structure_set (s, "decodebin3-flushing-stream-start",
Packit 971217
              G_TYPE_BOOLEAN, TRUE, NULL);
Packit 971217
          gst_pad_send_event (peer, custom_stream_start);
Packit 971217
        }
Packit 971217
Packit 971217
        eos = gst_event_new_eos ();
Packit 971217
        gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (eos),
Packit 971217
            CUSTOM_FINAL_EOS_QUARK, (gchar *) CUSTOM_FINAL_EOS_QUARK_DATA,
Packit 971217
            NULL);
Packit 971217
        gst_pad_send_event (peer, eos);
Packit 971217
        gst_object_unref (peer);
Packit 971217
      } else
Packit 971217
        GST_DEBUG_OBJECT (dbin, "no output");
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static GstPadProbeReturn
Packit 971217
multiqueue_src_probe (GstPad * pad, GstPadProbeInfo * info,
Packit 971217
    MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
Packit 971217
  GstDecodebin3 *dbin = slot->dbin;
Packit 971217
Packit 971217
  if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
Packit 971217
    GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (pad, "Got event %p %s", ev, GST_EVENT_TYPE_NAME (ev));
Packit 971217
    switch (GST_EVENT_TYPE (ev)) {
Packit 971217
      case GST_EVENT_STREAM_START:
Packit 971217
      {
Packit 971217
        GstStream *stream = NULL;
Packit 971217
        const GstStructure *s = gst_event_get_structure (ev);
Packit 971217
Packit 971217
        /* Drop STREAM_START events used to cleanup multiqueue */
Packit 971217
        if (s
Packit 971217
            && gst_structure_has_field (s,
Packit 971217
                "decodebin3-flushing-stream-start")) {
Packit 971217
          ret = GST_PAD_PROBE_HANDLED;
Packit 971217
          gst_event_unref (ev);
Packit 971217
          break;
Packit 971217
        }
Packit 971217
Packit 971217
        gst_event_parse_stream (ev, &stream);
Packit 971217
        if (stream == NULL) {
Packit 971217
          GST_ERROR_OBJECT (pad,
Packit 971217
              "Got a STREAM_START event without a GstStream");
Packit 971217
          break;
Packit 971217
        }
Packit 971217
        slot->is_drained = FALSE;
Packit 971217
        GST_DEBUG_OBJECT (pad, "Stream Start '%s'",
Packit 971217
            gst_stream_get_stream_id (stream));
Packit 971217
        if (slot->active_stream == NULL) {
Packit 971217
          slot->active_stream = stream;
Packit 971217
        } else if (slot->active_stream != stream) {
Packit 971217
          GST_FIXME_OBJECT (pad, "Handle stream changes (%s => %s) !",
Packit 971217
              gst_stream_get_stream_id (slot->active_stream),
Packit 971217
              gst_stream_get_stream_id (stream));
Packit 971217
          gst_object_unref (slot->active_stream);
Packit 971217
          slot->active_stream = stream;
Packit 971217
        } else
Packit 971217
          gst_object_unref (stream);
Packit 971217
#if 0                           /* Disabled because stream-start is pushed for every buffer on every unlinked pad */
Packit 971217
        {
Packit 971217
          gboolean is_active, is_requested;
Packit 971217
          /* Quick check to see if we're in the current selection */
Packit 971217
          /* FIXME : Re-check all slot<=>output mappings based on requested_selection */
Packit 971217
          SELECTION_LOCK (dbin);
Packit 971217
          GST_DEBUG_OBJECT (dbin, "Checking active selection");
Packit 971217
          is_active = stream_in_list (dbin->active_selection, stream_id);
Packit 971217
          GST_DEBUG_OBJECT (dbin, "Checking requested selection");
Packit 971217
          is_requested = stream_in_list (dbin->requested_selection, stream_id);
Packit 971217
          SELECTION_UNLOCK (dbin);
Packit 971217
          if (is_active)
Packit 971217
            GST_DEBUG_OBJECT (pad, "Slot in ACTIVE selection (output:%p)",
Packit 971217
                slot->output);
Packit 971217
          if (is_requested)
Packit 971217
            GST_DEBUG_OBJECT (pad, "Slot in REQUESTED selection (output:%p)",
Packit 971217
                slot->output);
Packit 971217
          else if (slot->output) {
Packit 971217
            GST_DEBUG_OBJECT (pad,
Packit 971217
                "Slot needs to be deactivated ? It's no longer in requested selection");
Packit 971217
          } else if (!is_active)
Packit 971217
            GST_DEBUG_OBJECT (pad,
Packit 971217
                "Slot in neither active nor requested selection");
Packit 971217
        }
Packit 971217
#endif
Packit 971217
      }
Packit 971217
        break;
Packit 971217
      case GST_EVENT_CAPS:
Packit 971217
      {
Packit 971217
        /* Configure the output slot if needed */
Packit 971217
        DecodebinOutputStream *output;
Packit 971217
        GstMessage *msg = NULL;
Packit 971217
        SELECTION_LOCK (dbin);
Packit 971217
        output = get_output_for_slot (slot);
Packit 971217
        if (output) {
Packit 971217
          reconfigure_output_stream (output, slot);
Packit 971217
          msg = is_selection_done (dbin);
Packit 971217
        }
Packit 971217
        SELECTION_UNLOCK (dbin);
Packit 971217
        if (msg)
Packit 971217
          gst_element_post_message ((GstElement *) slot->dbin, msg);
Packit 971217
      }
Packit 971217
        break;
Packit 971217
      case GST_EVENT_EOS:
Packit 971217
      {
Packit 971217
        gboolean was_drained = slot->is_drained;
Packit 971217
        slot->is_drained = TRUE;
Packit 971217
Packit 971217
        /* Custom EOS handling first */
Packit 971217
        if (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (ev),
Packit 971217
                CUSTOM_EOS_QUARK)) {
Packit 971217
          /* remove custom-eos */
Packit 971217
          gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (ev),
Packit 971217
              CUSTOM_EOS_QUARK, NULL, NULL);
Packit 971217
          GST_LOG_OBJECT (pad, "Received custom EOS");
Packit 971217
          ret = GST_PAD_PROBE_HANDLED;
Packit 971217
          SELECTION_LOCK (dbin);
Packit 971217
          if (slot->input == NULL) {
Packit 971217
            GST_DEBUG_OBJECT (pad,
Packit 971217
                "Got custom-eos from null input stream, remove output stream");
Packit 971217
            /* Remove the output */
Packit 971217
            if (slot->output) {
Packit 971217
              DecodebinOutputStream *output = slot->output;
Packit 971217
              dbin->output_streams =
Packit 971217
                  g_list_remove (dbin->output_streams, output);
Packit 971217
              free_output_stream (dbin, output);
Packit 971217
            }
Packit 971217
            slot->probe_id = 0;
Packit 971217
            dbin->slots = g_list_remove (dbin->slots, slot);
Packit 971217
            free_multiqueue_slot_async (dbin, slot);
Packit 971217
            ret = GST_PAD_PROBE_REMOVE;
Packit 971217
          } else if (!was_drained) {
Packit 971217
            check_all_slot_for_eos (dbin);
Packit 971217
          }
Packit 971217
          SELECTION_UNLOCK (dbin);
Packit 971217
          break;
Packit 971217
        }
Packit 971217
Packit 971217
        GST_FIXME_OBJECT (pad, "EOS on multiqueue source pad. input:%p",
Packit 971217
            slot->input);
Packit 971217
        if (slot->input == NULL) {
Packit 971217
          GstPad *peer;
Packit 971217
          GST_DEBUG_OBJECT (pad,
Packit 971217
              "last EOS for input, forwarding and removing slot");
Packit 971217
          peer = gst_pad_get_peer (pad);
Packit 971217
          if (peer) {
Packit 971217
            gst_pad_send_event (peer, ev);
Packit 971217
            gst_object_unref (peer);
Packit 971217
          } else {
Packit 971217
            gst_event_unref (ev);
Packit 971217
          }
Packit 971217
          SELECTION_LOCK (dbin);
Packit 971217
          /* FIXME : Shouldn't we try to re-assign the output instead of just
Packit 971217
           * removing it ? */
Packit 971217
          /* Remove the output */
Packit 971217
          if (slot->output) {
Packit 971217
            DecodebinOutputStream *output = slot->output;
Packit 971217
            dbin->output_streams = g_list_remove (dbin->output_streams, output);
Packit 971217
            free_output_stream (dbin, output);
Packit 971217
          }
Packit 971217
          slot->probe_id = 0;
Packit 971217
          dbin->slots = g_list_remove (dbin->slots, slot);
Packit 971217
          SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
          free_multiqueue_slot_async (dbin, slot);
Packit 971217
          ret = GST_PAD_PROBE_REMOVE;
Packit 971217
        } else if (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (ev),
Packit 971217
                CUSTOM_FINAL_EOS_QUARK)) {
Packit 971217
          GST_DEBUG_OBJECT (pad, "Got final eos, propagating downstream");
Packit 971217
        } else {
Packit 971217
          GST_DEBUG_OBJECT (pad, "Got regular eos (all_inputs_are_eos)");
Packit 971217
          /* drop current event as eos will be sent in check_all_slot_for_eos
Packit 971217
           * when all output streams are also eos */
Packit 971217
          ret = GST_PAD_PROBE_DROP;
Packit 971217
          SELECTION_LOCK (dbin);
Packit 971217
          check_all_slot_for_eos (dbin);
Packit 971217
          SELECTION_UNLOCK (dbin);
Packit 971217
        }
Packit 971217
      }
Packit 971217
        break;
Packit 971217
      default:
Packit 971217
        break;
Packit 971217
    }
Packit 971217
  } else if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) {
Packit 971217
    GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
Packit 971217
    switch (GST_QUERY_TYPE (query)) {
Packit 971217
      case GST_QUERY_CAPS:
Packit 971217
      {
Packit 971217
        GST_DEBUG_OBJECT (pad, "Intercepting CAPS query");
Packit 971217
        gst_query_set_caps_result (query, GST_CAPS_ANY);
Packit 971217
        ret = GST_PAD_PROBE_HANDLED;
Packit 971217
      }
Packit 971217
        break;
Packit 971217
Packit 971217
      case GST_QUERY_ACCEPT_CAPS:
Packit 971217
      {
Packit 971217
        GST_DEBUG_OBJECT (pad, "Intercepting Accept Caps query");
Packit 971217
        /* If the current decoder doesn't accept caps, we'll reconfigure
Packit 971217
         * on the actual caps event. So accept any caps. */
Packit 971217
        gst_query_set_accept_caps_result (query, TRUE);
Packit 971217
        ret = GST_PAD_PROBE_HANDLED;
Packit 971217
      }
Packit 971217
      default:
Packit 971217
        break;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
/* Create a new multiqueue slot for the given type
Packit 971217
 *
Packit 971217
 * It is up to the caller to know whether that slot is needed or not
Packit 971217
 * (and release it when no longer needed) */
Packit 971217
static MultiQueueSlot *
Packit 971217
create_new_slot (GstDecodebin3 * dbin, GstStreamType type)
Packit 971217
{
Packit 971217
  MultiQueueSlot *slot;
Packit 971217
  GstIterator *it = NULL;
Packit 971217
  GValue item = { 0, };
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin, "Creating new slot for type %s",
Packit 971217
      gst_stream_type_get_name (type));
Packit 971217
  slot = g_new0 (MultiQueueSlot, 1);
Packit 971217
  slot->dbin = dbin;
Packit 971217
Packit 971217
  slot->id = dbin->slot_id++;
Packit 971217
Packit 971217
  slot->type = type;
Packit 971217
  slot->sink_pad = gst_element_get_request_pad (dbin->multiqueue, "sink_%u");
Packit 971217
  if (slot->sink_pad == NULL)
Packit 971217
    goto fail;
Packit 971217
Packit 971217
  it = gst_pad_iterate_internal_links (slot->sink_pad);
Packit 971217
  if (!it || (gst_iterator_next (it, &item)) != GST_ITERATOR_OK
Packit 971217
      || ((slot->src_pad = g_value_dup_object (&item)) == NULL)) {
Packit 971217
    GST_ERROR ("Couldn't get srcpad from multiqueue for sink pad %s:%s",
Packit 971217
        GST_DEBUG_PAD_NAME (slot->src_pad));
Packit 971217
    goto fail;
Packit 971217
  }
Packit 971217
  gst_iterator_free (it);
Packit 971217
  g_value_reset (&item);
Packit 971217
Packit 971217
  g_object_set (slot->sink_pad, "group-id", (guint) type, NULL);
Packit 971217
Packit 971217
  /* Add event probe */
Packit 971217
  slot->probe_id =
Packit 971217
      gst_pad_add_probe (slot->src_pad,
Packit 971217
      GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
Packit 971217
      (GstPadProbeCallback) multiqueue_src_probe, slot, NULL);
Packit 971217
Packit 971217
  GST_DEBUG ("Created new slot %u (%p) (%s:%s)", slot->id, slot,
Packit 971217
      GST_DEBUG_PAD_NAME (slot->src_pad));
Packit 971217
Packit 971217
  dbin->slots = g_list_append (dbin->slots, slot);
Packit 971217
Packit 971217
  return slot;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
fail:
Packit 971217
  {
Packit 971217
    if (slot->sink_pad)
Packit 971217
      gst_element_release_request_pad (dbin->multiqueue, slot->sink_pad);
Packit 971217
    g_free (slot);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* Must be called with SELECTION_LOCK */
Packit 971217
static MultiQueueSlot *
Packit 971217
get_slot_for_input (GstDecodebin3 * dbin, DecodebinInputStream * input)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
  MultiQueueSlot *empty_slot = NULL;
Packit 971217
  GstStreamType input_type = 0;
Packit 971217
  gchar *stream_id = NULL;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin, "input %p (stream %p %s)",
Packit 971217
      input, input->active_stream,
Packit 971217
      input->
Packit 971217
      active_stream ? gst_stream_get_stream_id (input->active_stream) : "");
Packit 971217
Packit 971217
  if (input->active_stream) {
Packit 971217
    input_type = gst_stream_get_stream_type (input->active_stream);
Packit 971217
    stream_id = (gchar *) gst_stream_get_stream_id (input->active_stream);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Go over existing slots and check if there is already one for it */
Packit 971217
  for (tmp = dbin->slots; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    /* Already used input, return that one */
Packit 971217
    if (slot->input == input) {
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Returning already specified slot %d", slot->id);
Packit 971217
      return slot;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  /* Go amongst all unused slots of the right type and try to find a candidate */
Packit 971217
  for (tmp = dbin->slots; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    if (slot->input == NULL && input_type == slot->type) {
Packit 971217
      /* Remember this empty slot for later */
Packit 971217
      empty_slot = slot;
Packit 971217
      /* Check if available slot is of the same stream_id */
Packit 971217
      GST_LOG_OBJECT (dbin, "Checking candidate slot %d (active_stream:%p)",
Packit 971217
          slot->id, slot->active_stream);
Packit 971217
      if (stream_id && slot->active_stream) {
Packit 971217
        gchar *ostream_id =
Packit 971217
            (gchar *) gst_stream_get_stream_id (slot->active_stream);
Packit 971217
        GST_DEBUG_OBJECT (dbin, "Checking slot %d %s against %s", slot->id,
Packit 971217
            ostream_id, stream_id);
Packit 971217
        if (!g_strcmp0 (stream_id, ostream_id))
Packit 971217
          break;
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (empty_slot) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Re-using existing unused slot %d", empty_slot->id);
Packit 971217
    empty_slot->input = input;
Packit 971217
    return empty_slot;
Packit 971217
  }
Packit 971217
Packit 971217
  if (input_type)
Packit 971217
    return create_new_slot (dbin, input_type);
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
link_input_to_slot (DecodebinInputStream * input, MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  if (slot->input != NULL && slot->input != input) {
Packit 971217
    GST_ERROR_OBJECT (slot->dbin,
Packit 971217
        "Trying to link input to an already used slot");
Packit 971217
    return;
Packit 971217
  }
Packit 971217
  gst_pad_link_full (input->srcpad, slot->sink_pad, GST_PAD_LINK_CHECK_NOTHING);
Packit 971217
  slot->pending_stream = input->active_stream;
Packit 971217
  slot->input = input;
Packit 971217
}
Packit 971217
Packit 971217
#if 0
Packit 971217
static gboolean
Packit 971217
have_factory (GstDecodebin3 * dbin, GstCaps * caps,
Packit 971217
    GstElementFactoryListType ftype)
Packit 971217
{
Packit 971217
  gboolean ret = FALSE;
Packit 971217
  GList *res;
Packit 971217
Packit 971217
  g_mutex_lock (&dbin->factories_lock);
Packit 971217
  gst_decode_bin_update_factories_list (dbin);
Packit 971217
  if (ftype == GST_ELEMENT_FACTORY_TYPE_DECODER)
Packit 971217
    res =
Packit 971217
        gst_element_factory_list_filter (dbin->decoder_factories,
Packit 971217
        caps, GST_PAD_SINK, TRUE);
Packit 971217
  else
Packit 971217
    res =
Packit 971217
        gst_element_factory_list_filter (dbin->decodable_factories,
Packit 971217
        caps, GST_PAD_SINK, TRUE);
Packit 971217
  g_mutex_unlock (&dbin->factories_lock);
Packit 971217
Packit 971217
  if (res) {
Packit 971217
    ret = TRUE;
Packit 971217
    gst_plugin_feature_list_free (res);
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
#endif
Packit 971217
Packit 971217
static GstElement *
Packit 971217
create_element (GstDecodebin3 * dbin, GstStream * stream,
Packit 971217
    GstElementFactoryListType ftype)
Packit 971217
{
Packit 971217
  GList *res;
Packit 971217
  GstElement *element = NULL;
Packit 971217
  GstCaps *caps;
Packit 971217
Packit 971217
  g_mutex_lock (&dbin->factories_lock);
Packit 971217
  gst_decode_bin_update_factories_list (dbin);
Packit 971217
  caps = gst_stream_get_caps (stream);
Packit 971217
  if (ftype == GST_ELEMENT_FACTORY_TYPE_DECODER)
Packit 971217
    res =
Packit 971217
        gst_element_factory_list_filter (dbin->decoder_factories,
Packit 971217
        caps, GST_PAD_SINK, TRUE);
Packit 971217
  else
Packit 971217
    res =
Packit 971217
        gst_element_factory_list_filter (dbin->decodable_factories,
Packit 971217
        caps, GST_PAD_SINK, TRUE);
Packit 971217
  g_mutex_unlock (&dbin->factories_lock);
Packit 971217
Packit 971217
  if (res) {
Packit 971217
    element =
Packit 971217
        gst_element_factory_create ((GstElementFactory *) res->data, NULL);
Packit 971217
    GST_DEBUG ("Created element '%s'", GST_ELEMENT_NAME (element));
Packit 971217
    gst_plugin_feature_list_free (res);
Packit 971217
  } else {
Packit 971217
    GST_DEBUG ("Could not find an element for caps %" GST_PTR_FORMAT, caps);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_caps_unref (caps);
Packit 971217
  return element;
Packit 971217
}
Packit 971217
Packit 971217
/* FIXME : VERY NAIVE. ASSUMING FIRST ONE WILL WORK */
Packit 971217
static GstElement *
Packit 971217
create_decoder (GstDecodebin3 * dbin, GstStream * stream)
Packit 971217
{
Packit 971217
  return create_element (dbin, stream, GST_ELEMENT_FACTORY_TYPE_DECODER);
Packit 971217
}
Packit 971217
Packit 971217
static GstPadProbeReturn
Packit 971217
keyframe_waiter_probe (GstPad * pad, GstPadProbeInfo * info,
Packit 971217
    DecodebinOutputStream * output)
Packit 971217
{
Packit 971217
  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
Packit 971217
  /* If we have a keyframe, remove the probe and let all data through */
Packit 971217
  /* FIXME : HANDLE HEADER BUFFER ?? */
Packit 971217
  if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ||
Packit 971217
      GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
Packit 971217
    GST_DEBUG_OBJECT (pad,
Packit 971217
        "Buffer is keyframe or header, letting through and removing probe");
Packit 971217
    output->drop_probe_id = 0;
Packit 971217
    return GST_PAD_PROBE_REMOVE;
Packit 971217
  }
Packit 971217
  GST_DEBUG_OBJECT (pad, "Buffer is not a keyframe, dropping");
Packit 971217
  return GST_PAD_PROBE_DROP;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
reconfigure_output_stream (DecodebinOutputStream * output,
Packit 971217
    MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = output->dbin;
Packit 971217
  GstCaps *new_caps = (GstCaps *) gst_stream_get_caps (slot->active_stream);
Packit 971217
  gboolean needs_decoder;
Packit 971217
Packit 971217
  needs_decoder = gst_caps_can_intersect (new_caps, dbin->caps) != TRUE;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin,
Packit 971217
      "Reconfiguring output %p to slot %p, needs_decoder:%d", output, slot,
Packit 971217
      needs_decoder);
Packit 971217
Packit 971217
  /* FIXME : Maybe make the output un-hook itself automatically ? */
Packit 971217
  if (output->slot != NULL && output->slot != slot) {
Packit 971217
    GST_WARNING_OBJECT (dbin,
Packit 971217
        "Output still linked to another slot (%p)", output->slot);
Packit 971217
    gst_caps_unref (new_caps);
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Check if existing config is reusable as-is by checking if
Packit 971217
   * the existing decoder accepts the new caps, if not delete
Packit 971217
   * it and create a new one */
Packit 971217
  if (output->decoder) {
Packit 971217
    gboolean can_reuse_decoder;
Packit 971217
Packit 971217
    if (needs_decoder) {
Packit 971217
      can_reuse_decoder =
Packit 971217
          gst_pad_query_accept_caps (output->decoder_sink, new_caps);
Packit 971217
    } else
Packit 971217
      can_reuse_decoder = FALSE;
Packit 971217
Packit 971217
    if (can_reuse_decoder) {
Packit 971217
      if (output->type & GST_STREAM_TYPE_VIDEO && output->drop_probe_id == 0) {
Packit 971217
        GST_DEBUG_OBJECT (dbin, "Adding keyframe-waiter probe");
Packit 971217
        output->drop_probe_id =
Packit 971217
            gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER,
Packit 971217
            (GstPadProbeCallback) keyframe_waiter_probe, output, NULL);
Packit 971217
      }
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Reusing existing decoder for slot %p", slot);
Packit 971217
      if (output->linked == FALSE) {
Packit 971217
        gst_pad_link_full (slot->src_pad, output->decoder_sink,
Packit 971217
            GST_PAD_LINK_CHECK_NOTHING);
Packit 971217
        output->linked = TRUE;
Packit 971217
      }
Packit 971217
      gst_caps_unref (new_caps);
Packit 971217
      return;
Packit 971217
    }
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Removing old decoder for slot %p", slot);
Packit 971217
Packit 971217
    if (output->linked)
Packit 971217
      gst_pad_unlink (slot->src_pad, output->decoder_sink);
Packit 971217
    output->linked = FALSE;
Packit 971217
    if (output->drop_probe_id) {
Packit 971217
      gst_pad_remove_probe (slot->src_pad, output->drop_probe_id);
Packit 971217
      output->drop_probe_id = 0;
Packit 971217
    }
Packit 971217
Packit 971217
    if (!gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad, NULL)) {
Packit 971217
      GST_ERROR_OBJECT (dbin, "Could not release decoder pad");
Packit 971217
      gst_caps_unref (new_caps);
Packit 971217
      goto cleanup;
Packit 971217
    }
Packit 971217
Packit 971217
    gst_element_set_locked_state (output->decoder, TRUE);
Packit 971217
    gst_element_set_state (output->decoder, GST_STATE_NULL);
Packit 971217
Packit 971217
    gst_bin_remove ((GstBin *) dbin, output->decoder);
Packit 971217
    output->decoder = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_caps_unref (new_caps);
Packit 971217
Packit 971217
  gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
Packit 971217
  gst_object_replace ((GstObject **) & output->decoder_src, NULL);
Packit 971217
Packit 971217
  /* If a decoder is required, create one */
Packit 971217
  if (needs_decoder) {
Packit 971217
    /* If we don't have a decoder yet, instantiate one */
Packit 971217
    output->decoder = create_decoder (dbin, slot->active_stream);
Packit 971217
    if (output->decoder == NULL) {
Packit 971217
      GstCaps *caps;
Packit 971217
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
      /* FIXME : Should we be smarter if there's a missing decoder ?
Packit 971217
       * Should we deactivate that stream ? */
Packit 971217
      caps = gst_stream_get_caps (slot->active_stream);
Packit 971217
      gst_element_post_message (GST_ELEMENT_CAST (dbin),
Packit 971217
          gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps));
Packit 971217
      gst_caps_unref (caps);
Packit 971217
      SELECTION_LOCK (dbin);
Packit 971217
      goto cleanup;
Packit 971217
    }
Packit 971217
    if (!gst_bin_add ((GstBin *) dbin, output->decoder)) {
Packit 971217
      GST_ERROR_OBJECT (dbin, "could not add decoder to pipeline");
Packit 971217
      goto cleanup;
Packit 971217
    }
Packit 971217
    output->decoder_sink = gst_element_get_static_pad (output->decoder, "sink");
Packit 971217
    output->decoder_src = gst_element_get_static_pad (output->decoder, "src");
Packit 971217
    if (output->type & GST_STREAM_TYPE_VIDEO) {
Packit 971217
      GST_DEBUG_OBJECT (dbin, "Adding keyframe-waiter probe");
Packit 971217
      output->drop_probe_id =
Packit 971217
          gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER,
Packit 971217
          (GstPadProbeCallback) keyframe_waiter_probe, output, NULL);
Packit 971217
    }
Packit 971217
    if (gst_pad_link_full (slot->src_pad, output->decoder_sink,
Packit 971217
            GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) {
Packit 971217
      GST_ERROR_OBJECT (dbin, "could not link to %s:%s",
Packit 971217
          GST_DEBUG_PAD_NAME (output->decoder_sink));
Packit 971217
      goto cleanup;
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    output->decoder_src = gst_object_ref (slot->src_pad);
Packit 971217
    output->decoder_sink = NULL;
Packit 971217
  }
Packit 971217
  output->linked = TRUE;
Packit 971217
  if (!gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad,
Packit 971217
          output->decoder_src)) {
Packit 971217
    GST_ERROR_OBJECT (dbin, "Could not expose decoder pad");
Packit 971217
    goto cleanup;
Packit 971217
  }
Packit 971217
  if (output->src_exposed == FALSE) {
Packit 971217
    output->src_exposed = TRUE;
Packit 971217
    gst_element_add_pad (GST_ELEMENT_CAST (dbin), output->src_pad);
Packit 971217
  }
Packit 971217
Packit 971217
  if (output->decoder)
Packit 971217
    gst_element_sync_state_with_parent (output->decoder);
Packit 971217
Packit 971217
  output->slot = slot;
Packit 971217
  return;
Packit 971217
Packit 971217
cleanup:
Packit 971217
  {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Cleanup");
Packit 971217
    if (output->decoder_sink) {
Packit 971217
      gst_object_unref (output->decoder_sink);
Packit 971217
      output->decoder_sink = NULL;
Packit 971217
    }
Packit 971217
    if (output->decoder_src) {
Packit 971217
      gst_object_unref (output->decoder_src);
Packit 971217
      output->decoder_src = NULL;
Packit 971217
    }
Packit 971217
    if (output->decoder) {
Packit 971217
      gst_element_set_state (output->decoder, GST_STATE_NULL);
Packit 971217
      gst_bin_remove ((GstBin *) dbin, output->decoder);
Packit 971217
      output->decoder = NULL;
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static GstPadProbeReturn
Packit 971217
idle_reconfigure (GstPad * pad, GstPadProbeInfo * info, MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GstMessage *msg = NULL;
Packit 971217
  DecodebinOutputStream *output;
Packit 971217
Packit 971217
  SELECTION_LOCK (slot->dbin);
Packit 971217
  output = get_output_for_slot (slot);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (pad, "output : %p", output);
Packit 971217
Packit 971217
  if (output) {
Packit 971217
    reconfigure_output_stream (output, slot);
Packit 971217
    msg = is_selection_done (slot->dbin);
Packit 971217
  }
Packit 971217
  SELECTION_UNLOCK (slot->dbin);
Packit 971217
  if (msg)
Packit 971217
    gst_element_post_message ((GstElement *) slot->dbin, msg);
Packit 971217
Packit 971217
  return GST_PAD_PROBE_REMOVE;
Packit 971217
}
Packit 971217
Packit 971217
static MultiQueueSlot *
Packit 971217
find_slot_for_stream_id (GstDecodebin3 * dbin, const gchar * sid)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  for (tmp = dbin->slots; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    const gchar *stream_id;
Packit 971217
    if (slot->active_stream) {
Packit 971217
      stream_id = gst_stream_get_stream_id (slot->active_stream);
Packit 971217
      if (!g_strcmp0 (sid, stream_id))
Packit 971217
        return slot;
Packit 971217
    }
Packit 971217
    if (slot->pending_stream && slot->pending_stream != slot->active_stream) {
Packit 971217
      stream_id = gst_stream_get_stream_id (slot->pending_stream);
Packit 971217
      if (!g_strcmp0 (sid, stream_id))
Packit 971217
        return slot;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
/* This function handles the reassignment of a slot. Call this from
Packit 971217
 * the streaming thread of a slot. */
Packit 971217
static gboolean
Packit 971217
reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  DecodebinOutputStream *output;
Packit 971217
  MultiQueueSlot *target_slot = NULL;
Packit 971217
  GList *tmp;
Packit 971217
  const gchar *sid, *tsid;
Packit 971217
Packit 971217
  SELECTION_LOCK (dbin);
Packit 971217
  output = slot->output;
Packit 971217
Packit 971217
  if (G_UNLIKELY (slot->active_stream == NULL)) {
Packit 971217
    GST_DEBUG_OBJECT (slot->src_pad,
Packit 971217
        "Called on inactive slot (active_stream == NULL)");
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  if (G_UNLIKELY (output == NULL)) {
Packit 971217
    GST_DEBUG_OBJECT (slot->src_pad,
Packit 971217
        "Slot doesn't have any output to be removed");
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  sid = gst_stream_get_stream_id (slot->active_stream);
Packit 971217
  GST_DEBUG_OBJECT (slot->src_pad, "slot %s %p", sid, slot);
Packit 971217
Packit 971217
  /* Recheck whether this stream is still in the list of streams to deactivate */
Packit 971217
  if (stream_in_list (dbin->requested_selection, sid)) {
Packit 971217
    /* Stream is in the list of requested streams, don't remove */
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
    GST_DEBUG_OBJECT (slot->src_pad,
Packit 971217
        "Stream '%s' doesn't need to be deactivated", sid);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Unlink slot from output */
Packit 971217
  /* FIXME : Handle flushing ? */
Packit 971217
  /* FIXME : Handle outputs without decoders */
Packit 971217
  GST_DEBUG_OBJECT (slot->src_pad, "Unlinking from decoder %p",
Packit 971217
      output->decoder_sink);
Packit 971217
  if (output->decoder_sink)
Packit 971217
    gst_pad_unlink (slot->src_pad, output->decoder_sink);
Packit 971217
  output->linked = FALSE;
Packit 971217
  slot->output = NULL;
Packit 971217
  output->slot = NULL;
Packit 971217
  /* Remove sid from active selection */
Packit 971217
  for (tmp = dbin->active_selection; tmp; tmp = tmp->next)
Packit 971217
    if (!g_strcmp0 (sid, tmp->data)) {
Packit 971217
      dbin->active_selection = g_list_delete_link (dbin->active_selection, tmp);
Packit 971217
      break;
Packit 971217
    }
Packit 971217
Packit 971217
  /* Can we re-assign this output to a requested stream ? */
Packit 971217
  GST_DEBUG_OBJECT (slot->src_pad, "Attempting to re-assing output stream");
Packit 971217
  for (tmp = dbin->to_activate; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *tslot = find_slot_for_stream_id (dbin, tmp->data);
Packit 971217
    GST_LOG_OBJECT (tslot->src_pad, "Checking slot %p (output:%p , stream:%s)",
Packit 971217
        tslot, tslot->output, gst_stream_get_stream_id (tslot->active_stream));
Packit 971217
    if (tslot && tslot->type == output->type && tslot->output == NULL) {
Packit 971217
      GST_DEBUG_OBJECT (tslot->src_pad, "Using as reassigned slot");
Packit 971217
      target_slot = tslot;
Packit 971217
      tsid = tmp->data;
Packit 971217
      /* Pass target stream id to requested selection */
Packit 971217
      dbin->requested_selection =
Packit 971217
          g_list_append (dbin->requested_selection, g_strdup (tmp->data));
Packit 971217
      dbin->to_activate = g_list_remove (dbin->to_activate, tmp->data);
Packit 971217
      break;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (target_slot) {
Packit 971217
    GST_DEBUG_OBJECT (slot->src_pad, "Assigning output to slot %p '%s'",
Packit 971217
        target_slot, tsid);
Packit 971217
    target_slot->output = output;
Packit 971217
    output->slot = target_slot;
Packit 971217
    dbin->active_selection =
Packit 971217
        g_list_append (dbin->active_selection, (gchar *) tsid);
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
    /* Wakeup the target slot so that it retries to send events/buffers
Packit 971217
     * thereby triggering the output reconfiguration codepath */
Packit 971217
    gst_pad_add_probe (target_slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
Packit 971217
        (GstPadProbeCallback) idle_reconfigure, target_slot, NULL);
Packit 971217
    /* gst_pad_send_event (target_slot->src_pad, gst_event_new_reconfigure ()); */
Packit 971217
  } else {
Packit 971217
    GstMessage *msg;
Packit 971217
Packit 971217
    dbin->output_streams = g_list_remove (dbin->output_streams, output);
Packit 971217
    free_output_stream (dbin, output);
Packit 971217
    msg = is_selection_done (slot->dbin);
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
    if (msg)
Packit 971217
      gst_element_post_message ((GstElement *) slot->dbin, msg);
Packit 971217
  }
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/* Idle probe called when a slot should be unassigned from its output stream.
Packit 971217
 * This is needed to ensure nothing is flowing when unlinking the slot.
Packit 971217
 *
Packit 971217
 * Also, this method will search for a pending stream which could re-use
Packit 971217
 * the output stream. */
Packit 971217
static GstPadProbeReturn
Packit 971217
slot_unassign_probe (GstPad * pad, GstPadProbeInfo * info,
Packit 971217
    MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = slot->dbin;
Packit 971217
Packit 971217
  reassign_slot (dbin, slot);
Packit 971217
Packit 971217
  return GST_PAD_PROBE_REMOVE;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
handle_stream_switch (GstDecodebin3 * dbin, GList * select_streams,
Packit 971217
    guint32 seqnum)
Packit 971217
{
Packit 971217
  gboolean ret = TRUE;
Packit 971217
  GList *tmp;
Packit 971217
  /* List of slots to (de)activate. */
Packit 971217
  GList *to_deactivate = NULL;
Packit 971217
  GList *to_activate = NULL;
Packit 971217
  /* List of unknown stream id, most likely means the event
Packit 971217
   * should be sent upstream so that elements can expose the requested stream */
Packit 971217
  GList *unknown = NULL;
Packit 971217
  GList *to_reassign = NULL;
Packit 971217
  GList *future_request_streams = NULL;
Packit 971217
  GList *pending_streams = NULL;
Packit 971217
  GList *slots_to_reassign = NULL;
Packit 971217
Packit 971217
  SELECTION_LOCK (dbin);
Packit 971217
  if (G_UNLIKELY (seqnum != dbin->select_streams_seqnum)) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "New SELECT_STREAMS has arrived in the meantime");
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
  /* Remove pending select_streams */
Packit 971217
  g_list_free (dbin->pending_select_streams);
Packit 971217
  dbin->pending_select_streams = NULL;
Packit 971217
Packit 971217
  /* COMPARE the requested streams to the active and requested streams
Packit 971217
   * on multiqueue. */
Packit 971217
Packit 971217
  /* First check the slots to activate and which ones are unknown */
Packit 971217
  for (tmp = select_streams; tmp; tmp = tmp->next) {
Packit 971217
    const gchar *sid = (const gchar *) tmp->data;
Packit 971217
    MultiQueueSlot *slot;
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Checking stream '%s'", sid);
Packit 971217
    slot = find_slot_for_stream_id (dbin, sid);
Packit 971217
    /* Find the corresponding slot */
Packit 971217
    if (slot == NULL) {
Packit 971217
      if (stream_in_collection (dbin, (gchar *) sid)) {
Packit 971217
        pending_streams = g_list_append (pending_streams, (gchar *) sid);
Packit 971217
      } else {
Packit 971217
        GST_DEBUG_OBJECT (dbin, "We don't have a slot for stream '%s'", sid);
Packit 971217
        unknown = g_list_append (unknown, (gchar *) sid);
Packit 971217
      }
Packit 971217
    } else if (slot->output == NULL) {
Packit 971217
      GST_DEBUG_OBJECT (dbin, "We need to activate slot %p for stream '%s')",
Packit 971217
          slot, sid);
Packit 971217
      to_activate = g_list_append (to_activate, slot);
Packit 971217
    } else {
Packit 971217
      GST_DEBUG_OBJECT (dbin,
Packit 971217
          "Stream '%s' from slot %p is already active on output %p", sid, slot,
Packit 971217
          slot->output);
Packit 971217
      future_request_streams =
Packit 971217
          g_list_append (future_request_streams, (gchar *) sid);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = dbin->slots; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    /* For slots that have an output, check if it's part of the streams to
Packit 971217
     * be active */
Packit 971217
    if (slot->output) {
Packit 971217
      gboolean slot_to_deactivate = TRUE;
Packit 971217
Packit 971217
      if (slot->active_stream) {
Packit 971217
        if (stream_in_list (select_streams,
Packit 971217
                gst_stream_get_stream_id (slot->active_stream)))
Packit 971217
          slot_to_deactivate = FALSE;
Packit 971217
      }
Packit 971217
      if (slot_to_deactivate && slot->pending_stream
Packit 971217
          && slot->pending_stream != slot->active_stream) {
Packit 971217
        if (stream_in_list (select_streams,
Packit 971217
                gst_stream_get_stream_id (slot->pending_stream)))
Packit 971217
          slot_to_deactivate = FALSE;
Packit 971217
      }
Packit 971217
      if (slot_to_deactivate) {
Packit 971217
        GST_DEBUG_OBJECT (dbin,
Packit 971217
            "Slot %p (%s) should be deactivated, no longer used", slot,
Packit 971217
            slot->
Packit 971217
            active_stream ? gst_stream_get_stream_id (slot->active_stream) :
Packit 971217
            "NULL");
Packit 971217
        to_deactivate = g_list_append (to_deactivate, slot);
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (to_deactivate != NULL) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Check if we can reassign slots");
Packit 971217
    /* We need to compare what needs to be activated and deactivated in order
Packit 971217
     * to determine whether there are outputs that can be transferred */
Packit 971217
    /* Take the stream-id of the slots that are to be activated, for which there
Packit 971217
     * is a slot of the same type that needs to be deactivated */
Packit 971217
    tmp = to_deactivate;
Packit 971217
    while (tmp) {
Packit 971217
      MultiQueueSlot *slot_to_deactivate = (MultiQueueSlot *) tmp->data;
Packit 971217
      gboolean removeit = FALSE;
Packit 971217
      GList *tmp2, *next;
Packit 971217
      GST_DEBUG_OBJECT (dbin,
Packit 971217
          "Checking if slot to deactivate (%p) has a candidate slot to activate",
Packit 971217
          slot_to_deactivate);
Packit 971217
      for (tmp2 = to_activate; tmp2; tmp2 = tmp2->next) {
Packit 971217
        MultiQueueSlot *slot_to_activate = (MultiQueueSlot *) tmp2->data;
Packit 971217
        GST_DEBUG_OBJECT (dbin, "Comparing to slot %p", slot_to_activate);
Packit 971217
        if (slot_to_activate->type == slot_to_deactivate->type) {
Packit 971217
          GST_DEBUG_OBJECT (dbin, "Re-using");
Packit 971217
          to_reassign = g_list_append (to_reassign, (gchar *)
Packit 971217
              gst_stream_get_stream_id (slot_to_activate->active_stream));
Packit 971217
          slots_to_reassign =
Packit 971217
              g_list_append (slots_to_reassign, slot_to_deactivate);
Packit 971217
          to_activate = g_list_remove (to_activate, slot_to_activate);
Packit 971217
          removeit = TRUE;
Packit 971217
          break;
Packit 971217
        }
Packit 971217
      }
Packit 971217
      next = tmp->next;
Packit 971217
      if (removeit)
Packit 971217
        to_deactivate = g_list_delete_link (to_deactivate, tmp);
Packit 971217
      tmp = next;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = to_deactivate; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    GST_DEBUG_OBJECT (dbin,
Packit 971217
        "Really need to deactivate slot %p, but no available alternative",
Packit 971217
        slot);
Packit 971217
Packit 971217
    slots_to_reassign = g_list_append (slots_to_reassign, slot);
Packit 971217
  }
Packit 971217
Packit 971217
  /* The only slots left to activate are the ones that won't be reassigned and
Packit 971217
   * therefore really need to have a new output created */
Packit 971217
  for (tmp = to_activate; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    if (slot->active_stream)
Packit 971217
      future_request_streams =
Packit 971217
          g_list_append (future_request_streams,
Packit 971217
          (gchar *) gst_stream_get_stream_id (slot->active_stream));
Packit 971217
    else if (slot->pending_stream)
Packit 971217
      future_request_streams =
Packit 971217
          g_list_append (future_request_streams,
Packit 971217
          (gchar *) gst_stream_get_stream_id (slot->pending_stream));
Packit 971217
    else
Packit 971217
      GST_ERROR_OBJECT (dbin, "No stream for slot %p !!", slot);
Packit 971217
  }
Packit 971217
Packit 971217
  if (to_activate == NULL && pending_streams != NULL) {
Packit 971217
    GST_DEBUG_OBJECT (dbin, "Stream switch requested for future collection");
Packit 971217
    if (dbin->requested_selection)
Packit 971217
      g_list_free_full (dbin->requested_selection, g_free);
Packit 971217
    dbin->requested_selection =
Packit 971217
        g_list_copy_deep (select_streams, (GCopyFunc) g_strdup, NULL);
Packit 971217
    g_list_free (to_deactivate);
Packit 971217
    g_list_free (pending_streams);
Packit 971217
    to_deactivate = NULL;
Packit 971217
    pending_streams = NULL;
Packit 971217
  } else {
Packit 971217
    if (dbin->requested_selection)
Packit 971217
      g_list_free_full (dbin->requested_selection, g_free);
Packit 971217
    dbin->requested_selection =
Packit 971217
        g_list_copy_deep (future_request_streams, (GCopyFunc) g_strdup, NULL);
Packit 971217
    dbin->requested_selection =
Packit 971217
        g_list_concat (dbin->requested_selection,
Packit 971217
        g_list_copy_deep (pending_streams, (GCopyFunc) g_strdup, NULL));
Packit 971217
    if (dbin->to_activate)
Packit 971217
      g_list_free (dbin->to_activate);
Packit 971217
    dbin->to_activate = g_list_copy (to_reassign);
Packit 971217
  }
Packit 971217
Packit 971217
  dbin->selection_updated = TRUE;
Packit 971217
  SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
  if (unknown) {
Packit 971217
    GST_FIXME_OBJECT (dbin, "Got request for an unknown stream");
Packit 971217
    g_list_free (unknown);
Packit 971217
  }
Packit 971217
Packit 971217
  if (to_activate && !slots_to_reassign) {
Packit 971217
    for (tmp = to_activate; tmp; tmp = tmp->next) {
Packit 971217
      MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
      gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
Packit 971217
          (GstPadProbeCallback) idle_reconfigure, slot, NULL);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  /* For all streams to deactivate, add an idle probe where we will do
Packit 971217
   * the unassignment and switch over */
Packit 971217
  for (tmp = slots_to_reassign; tmp; tmp = tmp->next) {
Packit 971217
    MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
    gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
Packit 971217
        (GstPadProbeCallback) slot_unassign_probe, slot, NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  if (to_deactivate)
Packit 971217
    g_list_free (to_deactivate);
Packit 971217
  if (to_activate)
Packit 971217
    g_list_free (to_activate);
Packit 971217
  if (to_reassign)
Packit 971217
    g_list_free (to_reassign);
Packit 971217
  if (future_request_streams)
Packit 971217
    g_list_free (future_request_streams);
Packit 971217
  if (pending_streams)
Packit 971217
    g_list_free (pending_streams);
Packit 971217
  if (slots_to_reassign)
Packit 971217
    g_list_free (slots_to_reassign);
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static GstPadProbeReturn
Packit 971217
ghost_pad_event_probe (GstPad * pad, GstPadProbeInfo * info,
Packit 971217
    DecodebinOutputStream * output)
Packit 971217
{
Packit 971217
  GstPadProbeReturn ret = GST_PAD_PROBE_OK;
Packit 971217
  GstDecodebin3 *dbin = output->dbin;
Packit 971217
  GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (pad, "Got event %p %s", event, GST_EVENT_TYPE_NAME (event));
Packit 971217
Packit 971217
  switch (GST_EVENT_TYPE (event)) {
Packit 971217
    case GST_EVENT_SELECT_STREAMS:
Packit 971217
    {
Packit 971217
      GstPad *peer;
Packit 971217
      GList *streams = NULL;
Packit 971217
      guint32 seqnum = gst_event_get_seqnum (event);
Packit 971217
Packit 971217
      SELECTION_LOCK (dbin);
Packit 971217
      if (seqnum == dbin->select_streams_seqnum) {
Packit 971217
        SELECTION_UNLOCK (dbin);
Packit 971217
        GST_DEBUG_OBJECT (pad,
Packit 971217
            "Already handled/handling that SELECT_STREAMS event");
Packit 971217
        gst_event_unref (event);
Packit 971217
        ret = GST_PAD_PROBE_HANDLED;
Packit 971217
        break;
Packit 971217
      }
Packit 971217
      dbin->select_streams_seqnum = seqnum;
Packit 971217
      if (dbin->pending_select_streams != NULL) {
Packit 971217
        GST_LOG_OBJECT (dbin, "Replacing pending select streams");
Packit 971217
        g_list_free (dbin->pending_select_streams);
Packit 971217
        dbin->pending_select_streams = NULL;
Packit 971217
      }
Packit 971217
      gst_event_parse_select_streams (event, &streams);
Packit 971217
      dbin->pending_select_streams = g_list_copy (streams);
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
      /* Send event upstream */
Packit 971217
      if ((peer = gst_pad_get_peer (pad))) {
Packit 971217
        gst_pad_send_event (peer, event);
Packit 971217
        gst_object_unref (peer);
Packit 971217
      } else {
Packit 971217
        gst_event_unref (event);
Packit 971217
      }
Packit 971217
      /* Finally handle the switch */
Packit 971217
      if (streams) {
Packit 971217
        handle_stream_switch (dbin, streams, seqnum);
Packit 971217
        g_list_free_full (streams, g_free);
Packit 971217
      }
Packit 971217
      ret = GST_PAD_PROBE_HANDLED;
Packit 971217
    }
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_decodebin3_send_event (GstElement * element, GstEvent * event)
Packit 971217
{
Packit 971217
  GST_DEBUG_OBJECT (element, "event %s", GST_EVENT_TYPE_NAME (event));
Packit 971217
  if (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS) {
Packit 971217
    GstDecodebin3 *dbin = (GstDecodebin3 *) element;
Packit 971217
    GList *streams = NULL;
Packit 971217
    guint32 seqnum = gst_event_get_seqnum (event);
Packit 971217
Packit 971217
    SELECTION_LOCK (dbin);
Packit 971217
    if (seqnum == dbin->select_streams_seqnum) {
Packit 971217
      SELECTION_UNLOCK (dbin);
Packit 971217
      GST_DEBUG_OBJECT (dbin,
Packit 971217
          "Already handled/handling that SELECT_STREAMS event");
Packit 971217
      return TRUE;
Packit 971217
    }
Packit 971217
    dbin->select_streams_seqnum = seqnum;
Packit 971217
    if (dbin->pending_select_streams != NULL) {
Packit 971217
      GST_LOG_OBJECT (dbin, "Replacing pending select streams");
Packit 971217
      g_list_free (dbin->pending_select_streams);
Packit 971217
      dbin->pending_select_streams = NULL;
Packit 971217
    }
Packit 971217
    gst_event_parse_select_streams (event, &streams);
Packit 971217
    dbin->pending_select_streams = g_list_copy (streams);
Packit 971217
    SELECTION_UNLOCK (dbin);
Packit 971217
Packit 971217
    /* FIXME : We don't have an upstream ?? */
Packit 971217
#if 0
Packit 971217
    /* Send event upstream */
Packit 971217
    if ((peer = gst_pad_get_peer (pad))) {
Packit 971217
      gst_pad_send_event (peer, event);
Packit 971217
      gst_object_unref (peer);
Packit 971217
    }
Packit 971217
#endif
Packit 971217
    /* Finally handle the switch */
Packit 971217
    if (streams) {
Packit 971217
      handle_stream_switch (dbin, streams, seqnum);
Packit 971217
      g_list_free_full (streams, g_free);
Packit 971217
    }
Packit 971217
Packit 971217
    gst_event_unref (event);
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
  return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
static void
Packit 971217
free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  if (slot->probe_id)
Packit 971217
    gst_pad_remove_probe (slot->src_pad, slot->probe_id);
Packit 971217
  if (slot->input) {
Packit 971217
    if (slot->input->srcpad)
Packit 971217
      gst_pad_unlink (slot->input->srcpad, slot->sink_pad);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_element_release_request_pad (dbin->multiqueue, slot->sink_pad);
Packit 971217
  gst_object_replace ((GstObject **) & slot->sink_pad, NULL);
Packit 971217
  gst_object_replace ((GstObject **) & slot->src_pad, NULL);
Packit 971217
  gst_object_replace ((GstObject **) & slot->active_stream, NULL);
Packit 971217
  g_free (slot);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
free_multiqueue_slot_async (GstDecodebin3 * dbin, MultiQueueSlot * slot)
Packit 971217
{
Packit 971217
  GST_LOG_OBJECT (dbin, "pushing multiqueue slot on thread pool to free");
Packit 971217
  gst_element_call_async (GST_ELEMENT_CAST (dbin),
Packit 971217
      (GstElementCallAsyncFunc) free_multiqueue_slot, slot, NULL);
Packit 971217
}
Packit 971217
Packit 971217
/* Create a DecodebinOutputStream for a given type
Packit 971217
 * Note: It will be empty initially, it needs to be configured
Packit 971217
 * afterwards */
Packit 971217
static DecodebinOutputStream *
Packit 971217
create_output_stream (GstDecodebin3 * dbin, GstStreamType type)
Packit 971217
{
Packit 971217
  DecodebinOutputStream *res = g_new0 (DecodebinOutputStream, 1);
Packit 971217
  gchar *pad_name;
Packit 971217
  const gchar *prefix;
Packit 971217
  GstStaticPadTemplate *templ;
Packit 971217
  GstPadTemplate *ptmpl;
Packit 971217
  guint32 *counter;
Packit 971217
  GstPad *internal_pad;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (dbin, "Created new output stream %p for type %s",
Packit 971217
      res, gst_stream_type_get_name (type));
Packit 971217
Packit 971217
  res->type = type;
Packit 971217
  res->dbin = dbin;
Packit 971217
Packit 971217
  if (type & GST_STREAM_TYPE_VIDEO) {
Packit 971217
    templ = &video_src_template;
Packit 971217
    counter = &dbin->vpadcount;
Packit 971217
    prefix = "video";
Packit 971217
  } else if (type & GST_STREAM_TYPE_AUDIO) {
Packit 971217
    templ = &audio_src_template;
Packit 971217
    counter = &dbin->apadcount;
Packit 971217
    prefix = "audio";
Packit 971217
  } else if (type & GST_STREAM_TYPE_TEXT) {
Packit 971217
    templ = &text_src_template;
Packit 971217
    counter = &dbin->tpadcount;
Packit 971217
    prefix = "text";
Packit 971217
  } else {
Packit 971217
    templ = &src_template;
Packit 971217
    counter = &dbin->opadcount;
Packit 971217
    prefix = "src";
Packit 971217
  }
Packit 971217
Packit 971217
  pad_name = g_strdup_printf ("%s_%u", prefix, *counter);
Packit 971217
  *counter += 1;
Packit 971217
  ptmpl = gst_static_pad_template_get (templ);
Packit 971217
  res->src_pad = gst_ghost_pad_new_no_target_from_template (pad_name, ptmpl);
Packit 971217
  gst_object_unref (ptmpl);
Packit 971217
  g_free (pad_name);
Packit 971217
  gst_pad_set_active (res->src_pad, TRUE);
Packit 971217
  /* Put an event probe on the internal proxy pad to detect upstream
Packit 971217
   * events */
Packit 971217
  internal_pad =
Packit 971217
      (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) res->src_pad);
Packit 971217
  gst_pad_add_probe (internal_pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
Packit 971217
      (GstPadProbeCallback) ghost_pad_event_probe, res, NULL);
Packit 971217
  gst_object_unref (internal_pad);
Packit 971217
Packit 971217
  dbin->output_streams = g_list_append (dbin->output_streams, res);
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
free_output_stream (GstDecodebin3 * dbin, DecodebinOutputStream * output)
Packit 971217
{
Packit 971217
  if (output->slot) {
Packit 971217
    if (output->decoder_sink && output->decoder)
Packit 971217
      gst_pad_unlink (output->slot->src_pad, output->decoder_sink);
Packit 971217
Packit 971217
    output->slot->output = NULL;
Packit 971217
    output->slot = NULL;
Packit 971217
  }
Packit 971217
  gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
Packit 971217
  gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad, NULL);
Packit 971217
  gst_object_replace ((GstObject **) & output->decoder_src, NULL);
Packit 971217
  if (output->src_exposed) {
Packit 971217
    gst_element_remove_pad ((GstElement *) dbin, output->src_pad);
Packit 971217
  }
Packit 971217
  if (output->decoder) {
Packit 971217
    gst_element_set_locked_state (output->decoder, TRUE);
Packit 971217
    gst_element_set_state (output->decoder, GST_STATE_NULL);
Packit 971217
    gst_bin_remove ((GstBin *) dbin, output->decoder);
Packit 971217
  }
Packit 971217
  g_free (output);
Packit 971217
}
Packit 971217
Packit 971217
static GstStateChangeReturn
Packit 971217
gst_decodebin3_change_state (GstElement * element, GstStateChange transition)
Packit 971217
{
Packit 971217
  GstDecodebin3 *dbin = (GstDecodebin3 *) element;
Packit 971217
  GstStateChangeReturn ret;
Packit 971217
Packit 971217
  /* Upwards */
Packit 971217
  switch (transition) {
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
Packit 971217
  if (ret == GST_STATE_CHANGE_FAILURE)
Packit 971217
    goto beach;
Packit 971217
Packit 971217
  switch (transition) {
Packit 971217
    case GST_STATE_CHANGE_PAUSED_TO_READY:
Packit 971217
    {
Packit 971217
      GList *tmp;
Packit 971217
Packit 971217
      /* Free output streams */
Packit 971217
      for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
Packit 971217
        DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
Packit 971217
        free_output_stream (dbin, output);
Packit 971217
      }
Packit 971217
      g_list_free (dbin->output_streams);
Packit 971217
      dbin->output_streams = NULL;
Packit 971217
      /* Free multiqueue slots */
Packit 971217
      for (tmp = dbin->slots; tmp; tmp = tmp->next) {
Packit 971217
        MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
Packit 971217
        free_multiqueue_slot (dbin, slot);
Packit 971217
      }
Packit 971217
      g_list_free (dbin->slots);
Packit 971217
      dbin->slots = NULL;
Packit 971217
      dbin->current_group_id = GST_GROUP_ID_INVALID;
Packit 971217
      /* Free inputs */
Packit 971217
    }
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
beach:
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
gboolean
Packit 971217
gst_decodebin3_plugin_init (GstPlugin * plugin)
Packit 971217
{
Packit 971217
  GST_DEBUG_CATEGORY_INIT (decodebin3_debug, "decodebin3", 0, "decoder bin");
Packit 971217
Packit 971217
  return gst_element_register (plugin, "decodebin3", GST_RANK_NONE,
Packit 971217
      GST_TYPE_DECODEBIN3);
Packit 971217
}