Blame gst/encoding/gstencodebin.c

Packit 971217
/* GStreamer encoding bin
Packit 971217
 * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
Packit 971217
 *           (C) 2009 Nokia Corporation
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 <string.h>
Packit 971217
#include "gstencodebin.h"
Packit 971217
#include "gstsmartencoder.h"
Packit 971217
#include "gststreamsplitter.h"
Packit 971217
#include "gststreamcombiner.h"
Packit 971217
#include <gst/gst-i18n-plugin.h>
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:element-encodebin
Packit 971217
 * @title: encodebin
Packit 971217
 *
Packit 971217
 * EncodeBin provides a bin for encoding/muxing various streams according to
Packit 971217
 * a specified #GstEncodingProfile.
Packit 971217
 *
Packit 971217
 * Based on the profile that was set (via the #GstEncodeBin:profile property),
Packit 971217
 * EncodeBin will internally select and configure the required elements
Packit 971217
 * (encoders, muxers, but also audio and video converters) so that you can
Packit 971217
 * provide it raw or pre-encoded streams of data in input and have your
Packit 971217
 * encoded/muxed/converted stream in output.
Packit 971217
 *
Packit 971217
 * ## Features
Packit 971217
 *
Packit 971217
 * * Automatic encoder and muxer selection based on elements available on the
Packit 971217
 * system.
Packit 971217
 *
Packit 971217
 * * Conversion of raw audio/video streams (scaling, framerate conversion,
Packit 971217
 * colorspace conversion, samplerate conversion) to conform to the profile
Packit 971217
 * output format.
Packit 971217
 *
Packit 971217
 * * Variable number of streams. If the presence property for a stream encoding
Packit 971217
 * profile is 0, you can request any number of sink pads for it via the
Packit 971217
 * standard request pad gstreamer API or the #GstEncodeBin::request-pad action
Packit 971217
 * signal.
Packit 971217
 *
Packit 971217
 * * Avoid reencoding (passthrough). If the input stream is already encoded and is
Packit 971217
 * compatible with what the #GstEncodingProfile expects, then the stream won't
Packit 971217
 * be re-encoded but just passed through downstream to the muxer or the output.
Packit 971217
 *
Packit 971217
 * * Mix pre-encoded and raw streams as input. In addition to the passthrough
Packit 971217
 * feature above, you can feed both raw audio/video *AND* already-encoded data
Packit 971217
 * to a pad. #GstEncodeBin will take care of passing through the compatible
Packit 971217
 * segments and re-encoding the segments of media that need encoding.
Packit 971217
 *
Packit 971217
 * * Standard behaviour is to use a #GstEncodingContainerProfile to have both
Packit 971217
 * encoding and muxing performed. But you can also provide a single stream
Packit 971217
 * profile (like #GstEncodingAudioProfile) to only have the encoding done and
Packit 971217
 * handle the encoded output yourself.
Packit 971217
 *
Packit 971217
 * * Audio imperfection corrections. Incoming audio streams can have non perfect
Packit 971217
 * timestamps (jitter), like the streams coming from ASF files. #GstEncodeBin
Packit 971217
 * will automatically fix those imperfections for you. See
Packit 971217
 * #GstEncodeBin:audio-jitter-tolerance for more details.
Packit 971217
 *
Packit 971217
 * * Variable or Constant video framerate. If your #GstEncodingVideoProfile has
Packit 971217
 * the variableframerate property deactivated (default), then the incoming
Packit 971217
 * raw video stream will be retimestampped in order to produce a constant
Packit 971217
 * framerate.
Packit 971217
 *
Packit 971217
 * * Cross-boundary re-encoding. When feeding compatible pre-encoded streams that
Packit 971217
 * fall on segment boundaries, and for supported formats (right now only H263),
Packit 971217
 * the GOP will be decoded/reencoded when needed to produce an encoded output
Packit 971217
 * that fits exactly within the request GstSegment.
Packit 971217
 *
Packit 971217
 * * Missing plugin support. If a #GstElement is missing to encode/mux to the
Packit 971217
 * request profile formats, a missing-plugin #GstMessage will be posted on the
Packit 971217
 * #GstBus, allowing systems that support the missing-plugin system to offer the
Packit 971217
 * user a way to install the missing element.
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
Packit 971217
/* TODO/FIXME
Packit 971217
 *
Packit 971217
 * Handling mp3!xing!idv3 and theora!ogg tagsetting scenarios:
Packit 971217
 *  Once we have chosen a muxer:
Packit 971217
 *   When a new stream is requested:
Packit 971217
 *    If muxer isn't 'Formatter' OR doesn't have a TagSetter interface:
Packit 971217
 *      Find a Formatter for the given stream (preferably with TagSetter)
Packit 971217
 *       Insert that before muxer
Packit 971217
 **/
Packit 971217
Packit 971217
#define fast_pad_link(a,b) gst_pad_link_full((a),(b),GST_PAD_LINK_CHECK_NOTHING)
Packit 971217
#define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
Packit 971217
Packit 971217
typedef enum
Packit 971217
{
Packit 971217
  GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION = (1 << 0),
Packit 971217
  GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION = (1 << 1)
Packit 971217
} GstEncodeBinFlags;
Packit 971217
Packit 971217
#define GST_TYPE_ENCODEBIN_FLAGS (gst_encodebin_flags_get_type())
Packit 971217
GType gst_encodebin_flags_get_type (void);
Packit 971217
Packit 971217
/* generic templates */
Packit 971217
static GstStaticPadTemplate muxer_src_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
static GstStaticPadTemplate video_sink_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("video_%u",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_REQUEST,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
static GstStaticPadTemplate audio_sink_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("audio_%u",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_REQUEST,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
/* static GstStaticPadTemplate text_sink_template = */
Packit 971217
/* GST_STATIC_PAD_TEMPLATE ("text_%u", */
Packit 971217
/*     GST_PAD_SINK, */
Packit 971217
/*     GST_PAD_REQUEST, */
Packit 971217
/*     GST_STATIC_CAPS_ANY); */
Packit 971217
static GstStaticPadTemplate private_sink_template =
Packit 971217
GST_STATIC_PAD_TEMPLATE ("private_%u",
Packit 971217
    GST_PAD_SINK,
Packit 971217
    GST_PAD_REQUEST,
Packit 971217
    GST_STATIC_CAPS_ANY);
Packit 971217
Packit 971217
struct _GstEncodeBin
Packit 971217
{
Packit 971217
  GstBin parent;
Packit 971217
Packit 971217
  /* the profile field is only valid if it could be entirely setup */
Packit 971217
  GstEncodingProfile *profile;
Packit 971217
Packit 971217
  GList *streams;               /* List of StreamGroup, not sorted */
Packit 971217
Packit 971217
  GstElement *muxer;
Packit 971217
  /* Ghostpad with changing target */
Packit 971217
  GstPad *srcpad;
Packit 971217
Packit 971217
  /* TRUE if in PAUSED/PLAYING */
Packit 971217
  gboolean active;
Packit 971217
Packit 971217
  /* available muxers, encoders and parsers */
Packit 971217
  GList *muxers;
Packit 971217
  GList *formatters;
Packit 971217
  GList *encoders;
Packit 971217
  GList *parsers;
Packit 971217
Packit 971217
  /* Increasing counter for unique pad name */
Packit 971217
  guint last_pad_id;
Packit 971217
Packit 971217
  /* Cached caps for identification */
Packit 971217
  GstCaps *raw_video_caps;
Packit 971217
  GstCaps *raw_audio_caps;
Packit 971217
  /* GstCaps *raw_text_caps; */
Packit 971217
Packit 971217
  guint queue_buffers_max;
Packit 971217
  guint queue_bytes_max;
Packit 971217
  guint64 queue_time_max;
Packit 971217
Packit 971217
  guint64 tolerance;
Packit 971217
  gboolean avoid_reencoding;
Packit 971217
Packit 971217
  GstEncodeBinFlags flags;
Packit 971217
};
Packit 971217
Packit 971217
struct _GstEncodeBinClass
Packit 971217
{
Packit 971217
  GstBinClass parent;
Packit 971217
Packit 971217
  /* Action Signals */
Packit 971217
  GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
Packit 971217
  GstPad *(*request_profile_pad) (GstEncodeBin * encodebin,
Packit 971217
      const gchar * profilename);
Packit 971217
};
Packit 971217
Packit 971217
typedef struct _StreamGroup StreamGroup;
Packit 971217
Packit 971217
struct _StreamGroup
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin;
Packit 971217
  GstEncodingProfile *profile;
Packit 971217
  GstPad *ghostpad;             /* Sink ghostpad */
Packit 971217
  GstElement *inqueue;          /* Queue just after the ghostpad */
Packit 971217
  GstElement *splitter;
Packit 971217
  GList *converters;            /* List of conversion GstElement */
Packit 971217
  GstElement *capsfilter;       /* profile->restriction (if non-NULL/ANY) */
Packit 971217
  gulong inputfilter_caps_sid;
Packit 971217
  GstElement *encoder;          /* Encoder (can be NULL) */
Packit 971217
  GstElement *fakesink;         /* Fakesink (can be NULL) */
Packit 971217
  GstElement *combiner;
Packit 971217
  GstElement *parser;
Packit 971217
  GstElement *smartencoder;
Packit 971217
  GstElement *outfilter;        /* Output capsfilter (streamprofile.format) */
Packit 971217
  gulong outputfilter_caps_sid;
Packit 971217
  GstElement *formatter;
Packit 971217
  GstElement *outqueue;         /* Queue just before the muxer */
Packit 971217
  gulong restriction_sid;
Packit 971217
};
Packit 971217
Packit 971217
/* Default for queues (same defaults as queue element) */
Packit 971217
#define DEFAULT_QUEUE_BUFFERS_MAX  200
Packit 971217
#define DEFAULT_QUEUE_BYTES_MAX    10 * 1024 * 1024
Packit 971217
#define DEFAULT_QUEUE_TIME_MAX     GST_SECOND
Packit 971217
#define DEFAULT_AUDIO_JITTER_TOLERANCE 20 * GST_MSECOND
Packit 971217
#define DEFAULT_AVOID_REENCODING   FALSE
Packit 971217
#define DEFAULT_FLAGS              0
Packit 971217
Packit 971217
#define DEFAULT_RAW_CAPS			\
Packit 971217
  "video/x-raw; "				\
Packit 971217
  "audio/x-raw; "				\
Packit 971217
  "text/x-raw; "				\
Packit 971217
  "subpicture/x-dvd; "			\
Packit 971217
  "subpicture/x-pgs"
Packit 971217
Packit 971217
/* Properties */
Packit 971217
enum
Packit 971217
{
Packit 971217
  PROP_0,
Packit 971217
  PROP_PROFILE,
Packit 971217
  PROP_QUEUE_BUFFERS_MAX,
Packit 971217
  PROP_QUEUE_BYTES_MAX,
Packit 971217
  PROP_QUEUE_TIME_MAX,
Packit 971217
  PROP_AUDIO_JITTER_TOLERANCE,
Packit 971217
  PROP_AVOID_REENCODING,
Packit 971217
  PROP_FLAGS
Packit 971217
};
Packit 971217
Packit 971217
/* Signals */
Packit 971217
enum
Packit 971217
{
Packit 971217
  SIGNAL_REQUEST_PAD,
Packit 971217
  SIGNAL_REQUEST_PROFILE_PAD,
Packit 971217
  LAST_SIGNAL
Packit 971217
};
Packit 971217
Packit 971217
#define C_FLAGS(v) ((guint) v)
Packit 971217
Packit 971217
GType
Packit 971217
gst_encodebin_flags_get_type (void)
Packit 971217
{
Packit 971217
  static const GFlagsValue values[] = {
Packit 971217
    {C_FLAGS (GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION), "Do not use audio "
Packit 971217
          "conversion elements", "no-audio-conversion"},
Packit 971217
    {C_FLAGS (GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION), "Do not use video "
Packit 971217
          "conversion elements", "no-video-conversion"},
Packit 971217
    {0, NULL, NULL}
Packit 971217
  };
Packit 971217
  static volatile GType id = 0;
Packit 971217
Packit 971217
  if (g_once_init_enter ((gsize *) & id)) {
Packit 971217
    GType _id;
Packit 971217
Packit 971217
    _id = g_flags_register_static ("GstEncodeBinFlags", values);
Packit 971217
Packit 971217
    g_once_init_leave ((gsize *) & id, _id);
Packit 971217
  }
Packit 971217
Packit 971217
  return id;
Packit 971217
}
Packit 971217
Packit 971217
static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 };
Packit 971217
Packit 971217
static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
Packit 971217
Packit 971217
GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug);
Packit 971217
#define GST_CAT_DEFAULT gst_encode_bin_debug
Packit 971217
Packit 971217
G_DEFINE_TYPE (GstEncodeBin, gst_encode_bin, GST_TYPE_BIN);
Packit 971217
Packit 971217
static void gst_encode_bin_dispose (GObject * object);
Packit 971217
static void gst_encode_bin_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec);
Packit 971217
static void gst_encode_bin_get_property (GObject * object, guint prop_id,
Packit 971217
    GValue * value, GParamSpec * pspec);
Packit 971217
static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element,
Packit 971217
    GstStateChange transition);
Packit 971217
Packit 971217
static GstPad *gst_encode_bin_request_new_pad (GstElement * element,
Packit 971217
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
Packit 971217
static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad);
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile);
Packit 971217
static void gst_encode_bin_tear_down_profile (GstEncodeBin * ebin);
Packit 971217
static gboolean gst_encode_bin_setup_profile (GstEncodeBin * ebin,
Packit 971217
    GstEncodingProfile * profile);
Packit 971217
Packit 971217
static StreamGroup *_create_stream_group (GstEncodeBin * ebin,
Packit 971217
    GstEncodingProfile * sprof, const gchar * sinkpadname, GstCaps * sinkcaps,
Packit 971217
    gboolean * encoder_not_found);
Packit 971217
static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
Packit 971217
static void stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup);
Packit 971217
static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
Packit 971217
    GstCaps * caps);
Packit 971217
static GstPad *gst_encode_bin_request_profile_pad_signal (GstEncodeBin *
Packit 971217
    encodebin, const gchar * profilename);
Packit 971217
Packit 971217
static inline GstElement *_get_formatter (GstEncodeBin * ebin,
Packit 971217
    GstEncodingProfile * sprof);
Packit 971217
static void _post_missing_plugin_message (GstEncodeBin * ebin,
Packit 971217
    GstEncodingProfile * prof);
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_class_init (GstEncodeBinClass * klass)
Packit 971217
{
Packit 971217
  GObjectClass *gobject_klass;
Packit 971217
  GstElementClass *gstelement_klass;
Packit 971217
Packit 971217
  gobject_klass = (GObjectClass *) klass;
Packit 971217
  gstelement_klass = (GstElementClass *) klass;
Packit 971217
Packit 971217
  gobject_klass->dispose = gst_encode_bin_dispose;
Packit 971217
  gobject_klass->set_property = gst_encode_bin_set_property;
Packit 971217
  gobject_klass->get_property = gst_encode_bin_get_property;
Packit 971217
Packit 971217
  /* Properties */
Packit 971217
Packit 971217
  /**
Packit 971217
   * GstEncodeBin:profile:
Packit 971217
   *
Packit 971217
   * The #GstEncodingProfile to use. This property must be set before going
Packit 971217
   * to %GST_STATE_PAUSED or higher.
Packit 971217
   */
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_PROFILE,
Packit 971217
      g_param_spec_object ("profile", "Profile",
Packit 971217
          "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_QUEUE_BYTES_MAX,
Packit 971217
      g_param_spec_uint ("queue-bytes-max", "Max. size (kB)",
Packit 971217
          "Max. amount of data in the queue (bytes, 0=disable)",
Packit 971217
          0, G_MAXUINT, DEFAULT_QUEUE_BYTES_MAX,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_QUEUE_BUFFERS_MAX,
Packit 971217
      g_param_spec_uint ("queue-buffers-max", "Max. size (buffers)",
Packit 971217
          "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
Packit 971217
          DEFAULT_QUEUE_BUFFERS_MAX,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_QUEUE_TIME_MAX,
Packit 971217
      g_param_spec_uint64 ("queue-time-max", "Max. size (ns)",
Packit 971217
          "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
Packit 971217
          DEFAULT_QUEUE_TIME_MAX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_AUDIO_JITTER_TOLERANCE,
Packit 971217
      g_param_spec_uint64 ("audio-jitter-tolerance", "Audio jitter tolerance",
Packit 971217
          "Amount of timestamp jitter/imperfection to allow on audio streams before inserting/dropping samples (ns)",
Packit 971217
          0, G_MAXUINT64, DEFAULT_AUDIO_JITTER_TOLERANCE,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_AVOID_REENCODING,
Packit 971217
      g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
Packit 971217
          "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
Packit 971217
          DEFAULT_AVOID_REENCODING,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  /**
Packit 971217
   * GstEncodeBin:flags
Packit 971217
   *
Packit 971217
   * Control the behaviour of encodebin.
Packit 971217
   */
Packit 971217
  g_object_class_install_property (gobject_klass, PROP_FLAGS,
Packit 971217
      g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
Packit 971217
          GST_TYPE_ENCODEBIN_FLAGS, DEFAULT_FLAGS,
Packit 971217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 971217
Packit 971217
  /* Signals */
Packit 971217
  /**
Packit 971217
   * GstEncodeBin::request-pad
Packit 971217
   * @encodebin: a #GstEncodeBin instance
Packit 971217
   * @caps: a #GstCaps
Packit 971217
   *
Packit 971217
   * Use this method to request an unused sink request #GstPad that can take the
Packit 971217
   * provided @caps as input. You must release the pad with
Packit 971217
   * gst_element_release_request_pad() when you are done with it.
Packit 971217
   *
Packit 971217
   * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
Packit 971217
   * created or is available.
Packit 971217
   */
Packit 971217
  gst_encode_bin_signals[SIGNAL_REQUEST_PAD] =
Packit 971217
      g_signal_new ("request-pad", G_TYPE_FROM_CLASS (klass),
Packit 971217
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
Packit 971217
          request_pad), NULL, NULL, g_cclosure_marshal_generic,
Packit 971217
      GST_TYPE_PAD, 1, GST_TYPE_CAPS);
Packit 971217
Packit 971217
  /**
Packit 971217
   * GstEncodeBin::request-profile-pad
Packit 971217
   * @encodebin: a #GstEncodeBin instance
Packit 971217
   * @profilename: the name of a #GstEncodingProfile
Packit 971217
   *
Packit 971217
   * Use this method to request an unused sink request #GstPad from the profile
Packit 971217
   * @profilename. You must release the pad with
Packit 971217
   * gst_element_release_request_pad() when you are done with it.
Packit 971217
   *
Packit 971217
   * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
Packit 971217
   * created or is available.
Packit 971217
   */
Packit 971217
  gst_encode_bin_signals[SIGNAL_REQUEST_PROFILE_PAD] =
Packit 971217
      g_signal_new ("request-profile-pad", G_TYPE_FROM_CLASS (klass),
Packit 971217
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
Packit 971217
          request_profile_pad), NULL, NULL, g_cclosure_marshal_generic,
Packit 971217
      GST_TYPE_PAD, 1, G_TYPE_STRING);
Packit 971217
Packit 971217
  klass->request_pad = gst_encode_bin_request_pad_signal;
Packit 971217
  klass->request_profile_pad = gst_encode_bin_request_profile_pad_signal;
Packit 971217
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_klass,
Packit 971217
      &muxer_src_template);
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_klass,
Packit 971217
      &video_sink_template);
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_klass,
Packit 971217
      &audio_sink_template);
Packit 971217
  /* gst_element_class_add_static_pad_template (gstelement_klass, &text_sink_template); */
Packit 971217
  gst_element_class_add_static_pad_template (gstelement_klass,
Packit 971217
      &private_sink_template);
Packit 971217
Packit 971217
  gstelement_klass->change_state =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
Packit 971217
  gstelement_klass->request_new_pad =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
Packit 971217
  gstelement_klass->release_pad =
Packit 971217
      GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
Packit 971217
Packit 971217
  gst_element_class_set_static_metadata (gstelement_klass,
Packit 971217
      "Encoder Bin",
Packit 971217
      "Generic/Bin/Encoder",
Packit 971217
      "Convenience encoding/muxing element",
Packit 971217
      "Edward Hervey <edward.hervey@collabora.co.uk>");
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_dispose (GObject * object)
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) object;
Packit 971217
Packit 971217
  if (ebin->muxers)
Packit 971217
    gst_plugin_feature_list_free (ebin->muxers);
Packit 971217
  ebin->muxers = NULL;
Packit 971217
Packit 971217
  if (ebin->formatters)
Packit 971217
    gst_plugin_feature_list_free (ebin->formatters);
Packit 971217
  ebin->formatters = NULL;
Packit 971217
Packit 971217
  if (ebin->encoders)
Packit 971217
    gst_plugin_feature_list_free (ebin->encoders);
Packit 971217
  ebin->encoders = NULL;
Packit 971217
Packit 971217
  if (ebin->parsers)
Packit 971217
    gst_plugin_feature_list_free (ebin->parsers);
Packit 971217
  ebin->parsers = NULL;
Packit 971217
Packit 971217
  gst_encode_bin_tear_down_profile (ebin);
Packit 971217
Packit 971217
  if (ebin->raw_video_caps)
Packit 971217
    gst_caps_unref (ebin->raw_video_caps);
Packit 971217
  ebin->raw_video_caps = NULL;
Packit 971217
  if (ebin->raw_audio_caps)
Packit 971217
    gst_caps_unref (ebin->raw_audio_caps);
Packit 971217
  ebin->raw_audio_caps = NULL;
Packit 971217
  /* if (ebin->raw_text_caps) */
Packit 971217
  /*   gst_caps_unref (ebin->raw_text_caps); */
Packit 971217
Packit 971217
  G_OBJECT_CLASS (gst_encode_bin_parent_class)->dispose (object);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_init (GstEncodeBin * encode_bin)
Packit 971217
{
Packit 971217
  GstPadTemplate *tmpl;
Packit 971217
Packit 971217
  encode_bin->muxers =
Packit 971217
      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
Packit 971217
      GST_RANK_MARGINAL);
Packit 971217
Packit 971217
  encode_bin->formatters =
Packit 971217
      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
Packit 971217
      GST_RANK_SECONDARY);
Packit 971217
Packit 971217
  encode_bin->encoders =
Packit 971217
      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
Packit 971217
      GST_RANK_MARGINAL);
Packit 971217
Packit 971217
  encode_bin->parsers =
Packit 971217
      gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
Packit 971217
      GST_RANK_MARGINAL);
Packit 971217
Packit 971217
  encode_bin->raw_video_caps = gst_caps_from_string ("video/x-raw");
Packit 971217
  encode_bin->raw_audio_caps = gst_caps_from_string ("audio/x-raw");
Packit 971217
  /* encode_bin->raw_text_caps = */
Packit 971217
  /*     gst_caps_from_string ("text/x-raw"); */
Packit 971217
Packit 971217
  encode_bin->queue_buffers_max = DEFAULT_QUEUE_BUFFERS_MAX;
Packit 971217
  encode_bin->queue_bytes_max = DEFAULT_QUEUE_BYTES_MAX;
Packit 971217
  encode_bin->queue_time_max = DEFAULT_QUEUE_TIME_MAX;
Packit 971217
  encode_bin->tolerance = DEFAULT_AUDIO_JITTER_TOLERANCE;
Packit 971217
  encode_bin->avoid_reencoding = DEFAULT_AVOID_REENCODING;
Packit 971217
  encode_bin->flags = DEFAULT_FLAGS;
Packit 971217
Packit 971217
  tmpl = gst_static_pad_template_get (&muxer_src_template);
Packit 971217
  encode_bin->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
Packit 971217
  gst_object_unref (tmpl);
Packit 971217
  gst_pad_set_active (encode_bin->srcpad, TRUE);
Packit 971217
  gst_element_add_pad (GST_ELEMENT_CAST (encode_bin), encode_bin->srcpad);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_set_property (GObject * object, guint prop_id,
Packit 971217
    const GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) object;
Packit 971217
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_PROFILE:
Packit 971217
      gst_encode_bin_set_profile (ebin,
Packit 971217
          (GstEncodingProfile *) g_value_get_object (value));
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_BUFFERS_MAX:
Packit 971217
      ebin->queue_buffers_max = g_value_get_uint (value);
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_BYTES_MAX:
Packit 971217
      ebin->queue_bytes_max = g_value_get_uint (value);
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_TIME_MAX:
Packit 971217
      ebin->queue_time_max = g_value_get_uint64 (value);
Packit 971217
      break;
Packit 971217
    case PROP_AUDIO_JITTER_TOLERANCE:
Packit 971217
      ebin->tolerance = g_value_get_uint64 (value);
Packit 971217
      break;
Packit 971217
    case PROP_AVOID_REENCODING:
Packit 971217
      ebin->avoid_reencoding = g_value_get_boolean (value);
Packit 971217
      break;
Packit 971217
    case PROP_FLAGS:
Packit 971217
      ebin->flags = g_value_get_flags (value);
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_encode_bin_get_property (GObject * object, guint prop_id,
Packit 971217
    GValue * value, GParamSpec * pspec)
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) object;
Packit 971217
Packit 971217
  switch (prop_id) {
Packit 971217
    case PROP_PROFILE:
Packit 971217
      g_value_set_object (value, (GObject *) ebin->profile);
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_BUFFERS_MAX:
Packit 971217
      g_value_set_uint (value, ebin->queue_buffers_max);
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_BYTES_MAX:
Packit 971217
      g_value_set_uint (value, ebin->queue_bytes_max);
Packit 971217
      break;
Packit 971217
    case PROP_QUEUE_TIME_MAX:
Packit 971217
      g_value_set_uint64 (value, ebin->queue_time_max);
Packit 971217
      break;
Packit 971217
    case PROP_AUDIO_JITTER_TOLERANCE:
Packit 971217
      g_value_set_uint64 (value, ebin->tolerance);
Packit 971217
      break;
Packit 971217
    case PROP_AVOID_REENCODING:
Packit 971217
      g_value_set_boolean (value, ebin->avoid_reencoding);
Packit 971217
      break;
Packit 971217
    case PROP_FLAGS:
Packit 971217
      g_value_set_flags (value, ebin->flags);
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 inline gboolean
Packit 971217
are_raw_caps (const GstCaps * caps)
Packit 971217
{
Packit 971217
  GstCaps *raw = gst_static_caps_get (&default_raw_caps);
Packit 971217
  gboolean res = gst_caps_can_intersect (caps, raw);
Packit 971217
Packit 971217
  gst_caps_unref (raw);
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/* Returns the number of time a given stream profile is currently used
Packit 971217
 * in encodebin */
Packit 971217
static inline guint
Packit 971217
stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof)
Packit 971217
{
Packit 971217
  guint nbprofused = 0;
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  for (tmp = ebin->streams; tmp; tmp = tmp->next) {
Packit 971217
    StreamGroup *sgroup = (StreamGroup *) tmp->data;
Packit 971217
Packit 971217
    if (sgroup->profile == sprof)
Packit 971217
      nbprofused++;
Packit 971217
  }
Packit 971217
Packit 971217
  return nbprofused;
Packit 971217
}
Packit 971217
Packit 971217
static inline GstEncodingProfile *
Packit 971217
next_unused_stream_profile (GstEncodeBin * ebin, GType ptype,
Packit 971217
    const gchar * name, GstCaps * caps, GstEncodingProfile * previous_profile)
Packit 971217
{
Packit 971217
  GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT,
Packit 971217
      g_type_name (ptype), caps);
Packit 971217
Packit 971217
  if (G_UNLIKELY (ptype == G_TYPE_NONE && caps != NULL)) {
Packit 971217
    /* Identify the profile type based on raw caps */
Packit 971217
    if (gst_caps_can_intersect (ebin->raw_video_caps, caps))
Packit 971217
      ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
Packit 971217
    else if (gst_caps_can_intersect (ebin->raw_audio_caps, caps))
Packit 971217
      ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
Packit 971217
    /* else if (gst_caps_can_intersect (ebin->raw_text_caps, caps)) */
Packit 971217
    /*   ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
Packit 971217
    GST_DEBUG_OBJECT (ebin, "Detected profile type as being %s",
Packit 971217
        g_type_name (ptype));
Packit 971217
  }
Packit 971217
Packit 971217
  if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
Packit 971217
    const GList *tmp;
Packit 971217
Packit 971217
    if (name) {
Packit 971217
      /* If we have a name, try to find a profile with the same name */
Packit 971217
      tmp =
Packit 971217
          gst_encoding_container_profile_get_profiles
Packit 971217
          (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
Packit 971217
Packit 971217
      for (; tmp; tmp = tmp->next) {
Packit 971217
        GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
Packit 971217
        const gchar *profilename = gst_encoding_profile_get_name (sprof);
Packit 971217
Packit 971217
        if (profilename && !strcmp (name, profilename)) {
Packit 971217
          guint presence = gst_encoding_profile_get_presence (sprof);
Packit 971217
Packit 971217
          GST_DEBUG ("Found profile matching the requested name");
Packit 971217
Packit 971217
          if (!gst_encoding_profile_is_enabled (sprof)) {
Packit 971217
            GST_INFO_OBJECT (ebin, "%p is disabled, not using it", sprof);
Packit 971217
Packit 971217
            return NULL;
Packit 971217
          }
Packit 971217
Packit 971217
          if (presence == 0
Packit 971217
              || presence > stream_profile_used_count (ebin, sprof))
Packit 971217
            return sprof;
Packit 971217
Packit 971217
          GST_WARNING ("Matching stream already used");
Packit 971217
          return NULL;
Packit 971217
        }
Packit 971217
      }
Packit 971217
      GST_DEBUG
Packit 971217
          ("No profiles matching requested pad name, carrying on with normal stream matching");
Packit 971217
    }
Packit 971217
Packit 971217
    for (tmp =
Packit 971217
        gst_encoding_container_profile_get_profiles
Packit 971217
        (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp;
Packit 971217
        tmp = tmp->next) {
Packit 971217
      GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
Packit 971217
Packit 971217
      /* Pick an available Stream profile for which:
Packit 971217
       * * either it is of the compatible raw type,
Packit 971217
       * * OR we can pass it through directly without encoding
Packit 971217
       */
Packit 971217
      if (G_TYPE_FROM_INSTANCE (sprof) == ptype) {
Packit 971217
        guint presence = gst_encoding_profile_get_presence (sprof);
Packit 971217
        GST_DEBUG ("Found a stream profile with the same type");
Packit 971217
        if (!gst_encoding_profile_is_enabled (sprof)) {
Packit 971217
          GST_INFO_OBJECT (ebin, "%p is disabled, not using it", sprof);
Packit 971217
        } else if (presence == 0
Packit 971217
            || (presence > stream_profile_used_count (ebin, sprof))) {
Packit 971217
Packit 971217
          if (sprof != previous_profile)
Packit 971217
            return sprof;
Packit 971217
        }
Packit 971217
      } else if (caps && ptype == G_TYPE_NONE) {
Packit 971217
        GstCaps *outcaps;
Packit 971217
        gboolean res;
Packit 971217
Packit 971217
        outcaps = gst_encoding_profile_get_input_caps (sprof);
Packit 971217
        GST_DEBUG ("Unknown stream, seeing if it's compatible with %"
Packit 971217
            GST_PTR_FORMAT, outcaps);
Packit 971217
        res = gst_caps_can_intersect (outcaps, caps);
Packit 971217
        gst_caps_unref (outcaps);
Packit 971217
Packit 971217
        if (res && sprof != previous_profile)
Packit 971217
          return sprof;
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
request_pad_for_stream (GstEncodeBin * encodebin, GType ptype,
Packit 971217
    const gchar * name, GstCaps * caps)
Packit 971217
{
Packit 971217
  StreamGroup *sgroup = NULL;
Packit 971217
  GList *not_found_encoder_profs = NULL, *tmp;
Packit 971217
  GstEncodingProfile *sprof = NULL;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (encodebin, "name:%s caps:%" GST_PTR_FORMAT, name, caps);
Packit 971217
Packit 971217
  while (sgroup == NULL) {
Packit 971217
    gboolean encoder_not_found = FALSE;
Packit 971217
    /* Figure out if we have a unused GstEncodingProfile we can use for
Packit 971217
     * these caps */
Packit 971217
    sprof = next_unused_stream_profile (encodebin, ptype, name, caps, sprof);
Packit 971217
Packit 971217
    if (G_UNLIKELY (sprof == NULL))
Packit 971217
      goto no_stream_profile;
Packit 971217
Packit 971217
    sgroup = _create_stream_group (encodebin, sprof, name, caps,
Packit 971217
        &encoder_not_found);
Packit 971217
Packit 971217
    if (G_UNLIKELY (sgroup))
Packit 971217
      break;
Packit 971217
Packit 971217
    if (encoder_not_found) {
Packit 971217
      not_found_encoder_profs = g_list_prepend (not_found_encoder_profs, sprof);
Packit 971217
      if (name) {
Packit 971217
        GST_DEBUG ("Could not create an encoder for %s", name);
Packit 971217
        goto no_stream_group;
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      break;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (!sgroup)
Packit 971217
    goto no_stream_group;
Packit 971217
Packit 971217
  g_list_free (not_found_encoder_profs);
Packit 971217
  return sgroup->ghostpad;
Packit 971217
Packit 971217
no_stream_profile:
Packit 971217
  {
Packit 971217
    GST_WARNING_OBJECT (encodebin, "Couldn't find a compatible stream profile");
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
no_stream_group:
Packit 971217
  {
Packit 971217
    for (tmp = not_found_encoder_profs; tmp; tmp = tmp->next)
Packit 971217
      _post_missing_plugin_message (encodebin, tmp->data);
Packit 971217
    g_list_free (not_found_encoder_profs);
Packit 971217
Packit 971217
    GST_WARNING_OBJECT (encodebin, "Couldn't create a StreamGroup");
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
gst_encode_bin_request_new_pad (GstElement * element,
Packit 971217
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) element;
Packit 971217
  GstPad *res = NULL;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
Packit 971217
Packit 971217
  /* Identify the stream group (if name or caps have been provided) */
Packit 971217
  if (caps != NULL || name != NULL) {
Packit 971217
    res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps);
Packit 971217
  }
Packit 971217
Packit 971217
  if (res == NULL) {
Packit 971217
    GType ptype = G_TYPE_NONE;
Packit 971217
Packit 971217
    if (!strcmp (templ->name_template, "video_%u"))
Packit 971217
      ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
Packit 971217
    else if (!strcmp (templ->name_template, "audio_%u"))
Packit 971217
      ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
Packit 971217
    /* else if (!strcmp (templ->name_template, "text_%u")) */
Packit 971217
    /*   ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
Packit 971217
Packit 971217
    /* FIXME : Check uniqueness of pad */
Packit 971217
    /* FIXME : Check that the requested number is the last one, and if not,
Packit 971217
     * update the last_pad_id variable so that we don't create a pad with
Packit 971217
     * the same name/number in the future */
Packit 971217
Packit 971217
    res = request_pad_for_stream (ebin, ptype, name, NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps)
Packit 971217
{
Packit 971217
  GstPad *pad = request_pad_for_stream (encodebin, G_TYPE_NONE, NULL, caps);
Packit 971217
Packit 971217
  return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
gst_encode_bin_request_profile_pad_signal (GstEncodeBin * encodebin,
Packit 971217
    const gchar * profilename)
Packit 971217
{
Packit 971217
  GstPad *pad =
Packit 971217
      request_pad_for_stream (encodebin, G_TYPE_NONE, profilename, NULL);
Packit 971217
Packit 971217
  return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
Packit 971217
}
Packit 971217
Packit 971217
static inline StreamGroup *
Packit 971217
find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  for (tmp = ebin->streams; tmp; tmp = tmp->next) {
Packit 971217
    StreamGroup *sgroup = (StreamGroup *) tmp->data;
Packit 971217
    if (G_UNLIKELY (sgroup->ghostpad == pad))
Packit 971217
      return sgroup;
Packit 971217
  }
Packit 971217
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_release_pad (GstElement * element, GstPad * pad)
Packit 971217
{
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) element;
Packit 971217
  StreamGroup *sgroup;
Packit 971217
Packit 971217
  /* Find the associated StreamGroup */
Packit 971217
Packit 971217
  sgroup = find_stream_group_from_pad (ebin, pad);
Packit 971217
  if (G_UNLIKELY (sgroup == NULL))
Packit 971217
    goto no_stream_group;
Packit 971217
Packit 971217
  /* Release objects/data associated with the StreamGroup */
Packit 971217
  stream_group_remove (ebin, sgroup);
Packit 971217
Packit 971217
  return;
Packit 971217
Packit 971217
no_stream_group:
Packit 971217
  {
Packit 971217
    GST_WARNING_OBJECT (ebin, "Couldn't find corresponding StreamGroup");
Packit 971217
    return;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* Create a parser for the given stream profile */
Packit 971217
static inline GstElement *
Packit 971217
_get_parser (GstEncodeBin * ebin, GstEncodingProfile * sprof)
Packit 971217
{
Packit 971217
  GList *parsers1, *parsers, *tmp;
Packit 971217
  GstElement *parser = NULL;
Packit 971217
  GstElementFactory *parserfact = NULL;
Packit 971217
  GstCaps *format;
Packit 971217
Packit 971217
  format = gst_encoding_profile_get_format (sprof);
Packit 971217
Packit 971217
  GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
Packit 971217
Packit 971217
  /* FIXME : requesting twice the parsers twice is a bit ugly, we should
Packit 971217
   * have a method to request on more than one condition */
Packit 971217
  parsers1 =
Packit 971217
      gst_element_factory_list_filter (ebin->parsers, format,
Packit 971217
      GST_PAD_SRC, FALSE);
Packit 971217
  parsers =
Packit 971217
      gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
Packit 971217
  gst_plugin_feature_list_free (parsers1);
Packit 971217
Packit 971217
  if (G_UNLIKELY (parsers == NULL)) {
Packit 971217
    GST_DEBUG ("Couldn't find any compatible parsers");
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = parsers; tmp; tmp = tmp->next) {
Packit 971217
    /* FIXME : We're only picking the first one so far */
Packit 971217
    /* FIXME : signal the user if he wants this */
Packit 971217
    parserfact = (GstElementFactory *) tmp->data;
Packit 971217
    break;
Packit 971217
  }
Packit 971217
Packit 971217
  if (parserfact)
Packit 971217
    parser = gst_element_factory_create (parserfact, NULL);
Packit 971217
Packit 971217
  gst_plugin_feature_list_free (parsers);
Packit 971217
Packit 971217
beach:
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
Packit 971217
  return parser;
Packit 971217
}
Packit 971217
Packit 971217
static GstElement *
Packit 971217
_create_element_and_set_preset (GstElementFactory * factory,
Packit 971217
    const gchar * preset, const gchar * name, const gchar * preset_name)
Packit 971217
{
Packit 971217
  GstElement *res = NULL;
Packit 971217
Packit 971217
  GST_DEBUG ("Creating element from factory %s (preset factory name: %s"
Packit 971217
      " preset name: %s)", GST_OBJECT_NAME (factory), preset_name, preset);
Packit 971217
Packit 971217
  if (preset_name && g_strcmp0 (GST_OBJECT_NAME (factory), preset_name)) {
Packit 971217
    GST_DEBUG ("Got to use %s, not %s", preset_name, GST_OBJECT_NAME (factory));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  res = gst_element_factory_create (factory, name);
Packit 971217
Packit 971217
  if (preset && GST_IS_PRESET (res)) {
Packit 971217
    if (preset_name == NULL ||
Packit 971217
        g_strcmp0 (GST_OBJECT_NAME (factory), preset_name) == 0) {
Packit 971217
Packit 971217
      if (!gst_preset_load_preset (GST_PRESET (res), preset)) {
Packit 971217
        GST_WARNING ("Couldn't set preset [%s] on element [%s]",
Packit 971217
            preset, GST_OBJECT_NAME (factory));
Packit 971217
        gst_object_unref (res);
Packit 971217
        res = NULL;
Packit 971217
      }
Packit 971217
    } else {
Packit 971217
      GST_DEBUG ("Using a preset with no preset name, making use of the"
Packit 971217
          " proper element without setting any property");
Packit 971217
    }
Packit 971217
  }
Packit 971217
  /* Else we keep it */
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/* Create the encoder for the given stream profile */
Packit 971217
static inline GstElement *
Packit 971217
_get_encoder (GstEncodeBin * ebin, GstEncodingProfile * sprof)
Packit 971217
{
Packit 971217
  GList *encoders, *tmp;
Packit 971217
  GstElement *encoder = NULL;
Packit 971217
  GstElementFactory *encoderfact = NULL;
Packit 971217
  GstCaps *format;
Packit 971217
  const gchar *preset, *preset_name;
Packit 971217
Packit 971217
  format = gst_encoding_profile_get_format (sprof);
Packit 971217
  preset = gst_encoding_profile_get_preset (sprof);
Packit 971217
  preset_name = gst_encoding_profile_get_preset_name (sprof);
Packit 971217
Packit 971217
  GST_DEBUG ("Getting list of encoders for format %" GST_PTR_FORMAT, format);
Packit 971217
Packit 971217
  /* If stream caps are raw, return identity */
Packit 971217
  if (G_UNLIKELY (are_raw_caps (format))) {
Packit 971217
    GST_DEBUG ("Stream format is raw, returning identity as the encoder");
Packit 971217
    encoder = gst_element_factory_make ("identity", NULL);
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  encoders =
Packit 971217
      gst_element_factory_list_filter (ebin->encoders, format,
Packit 971217
      GST_PAD_SRC, FALSE);
Packit 971217
Packit 971217
  if (G_UNLIKELY (encoders == NULL) && sprof == ebin->profile) {
Packit 971217
    /* Special case: if the top-level profile is an encoder,
Packit 971217
     * it could be listed in our muxers (for example wavenc)
Packit 971217
     */
Packit 971217
    encoders = gst_element_factory_list_filter (ebin->muxers, format,
Packit 971217
        GST_PAD_SRC, FALSE);
Packit 971217
  }
Packit 971217
Packit 971217
  if (G_UNLIKELY (encoders == NULL)) {
Packit 971217
    GST_DEBUG ("Couldn't find any compatible encoders");
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = encoders; tmp; tmp = tmp->next) {
Packit 971217
    encoderfact = (GstElementFactory *) tmp->data;
Packit 971217
    if ((encoder = _create_element_and_set_preset (encoderfact, preset,
Packit 971217
                NULL, preset_name)))
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_plugin_feature_list_free (encoders);
Packit 971217
Packit 971217
beach:
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
Packit 971217
  return encoder;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
local_element_request_pad (GstElement * element, GstPadTemplate * templ,
Packit 971217
    const gchar * name, const GstCaps * caps)
Packit 971217
{
Packit 971217
  GstPad *newpad = NULL;
Packit 971217
  GstElementClass *oclass;
Packit 971217
Packit 971217
  oclass = GST_ELEMENT_GET_CLASS (element);
Packit 971217
Packit 971217
  if (oclass->request_new_pad)
Packit 971217
    newpad = (oclass->request_new_pad) (element, templ, name, caps);
Packit 971217
Packit 971217
  if (newpad)
Packit 971217
    gst_object_ref (newpad);
Packit 971217
Packit 971217
  return newpad;
Packit 971217
}
Packit 971217
Packit 971217
static GstPad *
Packit 971217
gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
Packit 971217
{
Packit 971217
  GstPad *ret = NULL;
Packit 971217
  GstPadPresence presence;
Packit 971217
Packit 971217
  /* If this function is ever exported, we need check the validity of `element'
Packit 971217
   * and `templ', and to make sure the template actually belongs to the
Packit 971217
   * element. */
Packit 971217
Packit 971217
  presence = GST_PAD_TEMPLATE_PRESENCE (templ);
Packit 971217
Packit 971217
  switch (presence) {
Packit 971217
    case GST_PAD_ALWAYS:
Packit 971217
    case GST_PAD_SOMETIMES:
Packit 971217
      ret = gst_element_get_static_pad (element, templ->name_template);
Packit 971217
      if (!ret && presence == GST_PAD_ALWAYS)
Packit 971217
        g_warning
Packit 971217
            ("Element %s has an ALWAYS template %s, but no pad of the same name",
Packit 971217
            GST_OBJECT_NAME (element), templ->name_template);
Packit 971217
      break;
Packit 971217
Packit 971217
    case GST_PAD_REQUEST:
Packit 971217
      ret = gst_element_request_pad (element, templ, NULL, NULL);
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
/* FIXME : Improve algorithm for finding compatible muxer sink pad */
Packit 971217
static inline GstPad *
Packit 971217
get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
Packit 971217
    GstCaps * sinkcaps)
Packit 971217
{
Packit 971217
  GstPad *sinkpad;
Packit 971217
  GstPadTemplate *srctempl = NULL;
Packit 971217
  GstPadTemplate *sinktempl;
Packit 971217
Packit 971217
  if (encoder) {
Packit 971217
    GstPad *srcpad;
Packit 971217
    srcpad = gst_element_get_static_pad (encoder, "src");
Packit 971217
Packit 971217
    srctempl = gst_pad_get_pad_template (srcpad);
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (ebin,
Packit 971217
        "Attempting to find pad from muxer %s compatible with %s:%s",
Packit 971217
        GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad));
Packit 971217
Packit 971217
    gst_object_unref (srcpad);
Packit 971217
    sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
Packit 971217
    gst_object_unref (srctempl);
Packit 971217
  } else {
Packit 971217
    srctempl =
Packit 971217
        gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
Packit 971217
        sinkcaps);
Packit 971217
    g_assert (srctempl != NULL);
Packit 971217
    sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
Packit 971217
    g_object_unref (srctempl);
Packit 971217
  }
Packit 971217
Packit 971217
  if (G_UNLIKELY (sinktempl == NULL))
Packit 971217
    goto no_template;
Packit 971217
Packit 971217
  sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl);
Packit 971217
Packit 971217
  return sinkpad;
Packit 971217
Packit 971217
no_template:
Packit 971217
  {
Packit 971217
    GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer");
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_has_class (GstElement * element, const gchar * classname)
Packit 971217
{
Packit 971217
  GstElementClass *klass;
Packit 971217
  const gchar *value;
Packit 971217
Packit 971217
  klass = GST_ELEMENT_GET_CLASS (element);
Packit 971217
  value = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);
Packit 971217
  if (!value)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return strstr (value, classname) != NULL;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_profile_restriction_caps_cb (GstEncodingProfile * profile,
Packit 971217
    GParamSpec * arg G_GNUC_UNUSED, StreamGroup * group)
Packit 971217
{
Packit 971217
  GstCaps *restriction = gst_encoding_profile_get_restriction (profile);
Packit 971217
Packit 971217
  g_object_set (group->capsfilter, "caps", restriction, NULL);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_capsfilter_force_format (GstPad * pad,
Packit 971217
    GParamSpec * arg G_GNUC_UNUSED, gulong * signal_id)
Packit 971217
{
Packit 971217
  GstCaps *caps;
Packit 971217
  GstStructure *structure;
Packit 971217
Packit 971217
  g_object_get (pad, "caps", &caps, NULL);
Packit 971217
  caps = gst_caps_copy (caps);
Packit 971217
Packit 971217
  structure = gst_caps_get_structure (caps, 0);
Packit 971217
  gst_structure_remove_field (structure, "streamheader");
Packit 971217
  GST_DEBUG_OBJECT (pad, "Forcing caps to %" GST_PTR_FORMAT, caps);
Packit 971217
  g_object_set (GST_OBJECT_PARENT (pad), "caps", caps, NULL);
Packit 971217
  g_signal_handler_disconnect (pad, *signal_id);
Packit 971217
  *signal_id = 0;
Packit 971217
  gst_caps_unref (caps);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_set_group_caps_format (StreamGroup * sgroup, GstEncodingProfile * prof,
Packit 971217
    GstCaps * format)
Packit 971217
{
Packit 971217
  g_object_set (sgroup->outfilter, "caps", format, NULL);
Packit 971217
Packit 971217
  if (!gst_encoding_profile_get_allow_dynamic_output (prof)) {
Packit 971217
    if (!sgroup->outputfilter_caps_sid) {
Packit 971217
      sgroup->outputfilter_caps_sid =
Packit 971217
          g_signal_connect (sgroup->outfilter->sinkpads->data,
Packit 971217
          "notify::caps", G_CALLBACK (_capsfilter_force_format),
Packit 971217
          &sgroup->outputfilter_caps_sid);
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_post_missing_plugin_message (GstEncodeBin * ebin, GstEncodingProfile * prof)
Packit 971217
{
Packit 971217
  GstCaps *format;
Packit 971217
  format = gst_encoding_profile_get_format (prof);
Packit 971217
Packit 971217
  GST_ERROR_OBJECT (ebin,
Packit 971217
      "Couldn't create encoder with preset %s and preset name %s"
Packit 971217
      " for format %" GST_PTR_FORMAT,
Packit 971217
      GST_STR_NULL (gst_encoding_profile_get_preset (prof)),
Packit 971217
      GST_STR_NULL (gst_encoding_profile_get_preset_name (prof)), format);
Packit 971217
Packit 971217
  /* missing plugin support */
Packit 971217
  gst_element_post_message (GST_ELEMENT_CAST (ebin),
Packit 971217
      gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
Packit 971217
  GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
Packit 971217
      ("Couldn't create encoder for format %" GST_PTR_FORMAT, format));
Packit 971217
Packit 971217
  gst_caps_unref (format);
Packit 971217
}
Packit 971217
Packit 971217
static GstPadProbeReturn
Packit 971217
_missing_plugin_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
Packit 971217
{
Packit 971217
  StreamGroup *sgroup = udata;
Packit 971217
  GstEncodeBin *ebin = sgroup->ebin;
Packit 971217
Packit 971217
  _post_missing_plugin_message (ebin, sgroup->profile);
Packit 971217
Packit 971217
  return GST_PAD_PROBE_OK;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
_set_up_fake_encoder_pad_probe (GstEncodeBin * ebin, StreamGroup * sgroup)
Packit 971217
{
Packit 971217
  GstPad *pad = gst_element_get_static_pad (sgroup->fakesink, "sink");
Packit 971217
Packit 971217
  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, _missing_plugin_probe,
Packit 971217
      sgroup, NULL);
Packit 971217
Packit 971217
  gst_object_unref (pad);
Packit 971217
}
Packit 971217
Packit 971217
/* FIXME : Add handling of streams that don't require conversion elements */
Packit 971217
/*
Packit 971217
 * Create the elements, StreamGroup, add the sink pad, link it to the muxer
Packit 971217
 *
Packit 971217
 * sinkpadname: If non-NULL, that name will be assigned to the sink ghost pad
Packit 971217
 * sinkcaps: If non-NULL will be used to figure out how to setup the group
Packit 971217
 * encoder_not_found: If non NULL, set to TRUE if failure happened because
Packit 971217
 * the encoder could not be found
Packit 971217
 */
Packit 971217
static StreamGroup *
Packit 971217
_create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
Packit 971217
    const gchar * sinkpadname, GstCaps * sinkcaps, gboolean * encoder_not_found)
Packit 971217
{
Packit 971217
  StreamGroup *sgroup = NULL;
Packit 971217
  GstPad *sinkpad, *srcpad = NULL, *muxerpad = NULL;
Packit 971217
  /* Element we will link to the encoder */
Packit 971217
  GstElement *last = NULL;
Packit 971217
  GstElement *encoder = NULL;
Packit 971217
  GList *tmp, *tosync = NULL;
Packit 971217
  GstCaps *format, *restriction;
Packit 971217
  const gchar *missing_element_name;
Packit 971217
Packit 971217
  format = gst_encoding_profile_get_format (sprof);
Packit 971217
  restriction = gst_encoding_profile_get_restriction (sprof);
Packit 971217
Packit 971217
  GST_DEBUG ("Creating group. format %" GST_PTR_FORMAT ", for caps %"
Packit 971217
      GST_PTR_FORMAT, format, sinkcaps);
Packit 971217
  GST_DEBUG ("avoid_reencoding:%d", ebin->avoid_reencoding);
Packit 971217
Packit 971217
  sgroup = g_slice_new0 (StreamGroup);
Packit 971217
  sgroup->ebin = ebin;
Packit 971217
  sgroup->profile = sprof;
Packit 971217
Packit 971217
  /* NOTE for people reading this code:
Packit 971217
   *
Packit 971217
   * We construct the group starting by the furthest downstream element
Packit 971217
   * and making our way up adding/syncing/linking as we go.
Packit 971217
   *
Packit 971217
   * There are two parallel paths:
Packit 971217
   * * One for raw data which goes through converters and encoders
Packit 971217
   * * One for already encoded data
Packit 971217
   */
Packit 971217
Packit 971217
  /* Muxer.
Packit 971217
   * If we are handling a container profile, figure out if the muxer has a
Packit 971217
   * sinkpad compatible with the selected profile */
Packit 971217
  if (ebin->muxer) {
Packit 971217
    muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
Packit 971217
    if (G_UNLIKELY (muxerpad == NULL))
Packit 971217
      goto no_muxer_pad;
Packit 971217
Packit 971217
  }
Packit 971217
Packit 971217
  /* Output Queue.
Packit 971217
   * The actual queueing will be done in the input queue, but some queuing
Packit 971217
   * after the encoder can be beneficial for encoding performance. */
Packit 971217
  last = sgroup->outqueue = gst_element_factory_make ("queue", NULL);
Packit 971217
  g_object_set (sgroup->outqueue, "max-size-buffers", (guint) 0,
Packit 971217
      "max-size-bytes", (guint) 0, "max-size-time", (guint64) 3 * GST_SECOND,
Packit 971217
      "silent", TRUE, NULL);
Packit 971217
Packit 971217
  gst_bin_add (GST_BIN (ebin), sgroup->outqueue);
Packit 971217
  tosync = g_list_append (tosync, sgroup->outqueue);
Packit 971217
  srcpad = gst_element_get_static_pad (sgroup->outqueue, "src");
Packit 971217
  if (muxerpad) {
Packit 971217
    if (G_UNLIKELY (fast_pad_link (srcpad, muxerpad) != GST_PAD_LINK_OK)) {
Packit 971217
      goto muxer_link_failure;
Packit 971217
    }
Packit 971217
    gst_object_unref (muxerpad);
Packit 971217
  } else {
Packit 971217
    gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), srcpad);
Packit 971217
  }
Packit 971217
  gst_object_unref (srcpad);
Packit 971217
  srcpad = NULL;
Packit 971217
Packit 971217
  /* Check if we need a formatter
Packit 971217
   * If we have no muxer or
Packit 971217
   * if the muxer isn't a formatter and doesn't implement the tagsetter interface
Packit 971217
   */
Packit 971217
  if (!ebin->muxer || (!GST_IS_TAG_SETTER (ebin->muxer)
Packit 971217
          && !_has_class (ebin->muxer, "Formatter"))) {
Packit 971217
    sgroup->formatter = _get_formatter (ebin, sprof);
Packit 971217
    if (sgroup->formatter) {
Packit 971217
      GST_DEBUG ("Adding formatter for %" GST_PTR_FORMAT, format);
Packit 971217
Packit 971217
      gst_bin_add (GST_BIN (ebin), sgroup->formatter);
Packit 971217
      tosync = g_list_append (tosync, sgroup->formatter);
Packit 971217
      if (G_UNLIKELY (!fast_element_link (sgroup->formatter, last)))
Packit 971217
        goto formatter_link_failure;
Packit 971217
      last = sgroup->formatter;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
Packit 971217
  /* Output capsfilter
Packit 971217
   * This will receive the format caps from the streamprofile */
Packit 971217
  GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
Packit 971217
  sgroup->outfilter = gst_element_factory_make ("capsfilter", NULL);
Packit 971217
  _set_group_caps_format (sgroup, sprof, format);
Packit 971217
Packit 971217
  gst_bin_add (GST_BIN (ebin), sgroup->outfilter);
Packit 971217
  tosync = g_list_append (tosync, sgroup->outfilter);
Packit 971217
  if (G_UNLIKELY (!fast_element_link (sgroup->outfilter, last)))
Packit 971217
    goto outfilter_link_failure;
Packit 971217
  last = sgroup->outfilter;
Packit 971217
Packit 971217
Packit 971217
  sgroup->parser = _get_parser (ebin, sprof);
Packit 971217
Packit 971217
  if (sgroup->parser != NULL) {
Packit 971217
    GST_DEBUG ("Got a parser %s", GST_ELEMENT_NAME (sgroup->parser));
Packit 971217
    gst_bin_add (GST_BIN (ebin), sgroup->parser);
Packit 971217
    tosync = g_list_append (tosync, sgroup->parser);
Packit 971217
    if (G_UNLIKELY (!gst_element_link (sgroup->parser, last)))
Packit 971217
      goto parser_link_failure;
Packit 971217
    last = sgroup->parser;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Stream combiner */
Packit 971217
  sgroup->combiner = g_object_new (GST_TYPE_STREAM_COMBINER, NULL);
Packit 971217
Packit 971217
  gst_bin_add (GST_BIN (ebin), sgroup->combiner);
Packit 971217
  tosync = g_list_append (tosync, sgroup->combiner);
Packit 971217
  if (G_UNLIKELY (!fast_element_link (sgroup->combiner, last)))
Packit 971217
    goto combiner_link_failure;
Packit 971217
Packit 971217
Packit 971217
  /* Stream splitter */
Packit 971217
  sgroup->splitter = g_object_new (GST_TYPE_STREAM_SPLITTER, NULL);
Packit 971217
Packit 971217
  gst_bin_add (GST_BIN (ebin), sgroup->splitter);
Packit 971217
  tosync = g_list_append (tosync, sgroup->splitter);
Packit 971217
Packit 971217
  /* Input queue
Packit 971217
   * FIXME : figure out what max-size to use for the input queue */
Packit 971217
  sgroup->inqueue = gst_element_factory_make ("queue", NULL);
Packit 971217
  g_object_set (sgroup->inqueue, "max-size-buffers",
Packit 971217
      (guint) ebin->queue_buffers_max, "max-size-bytes",
Packit 971217
      (guint) ebin->queue_bytes_max, "max-size-time",
Packit 971217
      (guint64) ebin->queue_time_max, "silent", TRUE, NULL);
Packit 971217
Packit 971217
  gst_bin_add (GST_BIN (ebin), sgroup->inqueue);
Packit 971217
  tosync = g_list_append (tosync, sgroup->inqueue);
Packit 971217
  if (G_UNLIKELY (!fast_element_link (sgroup->inqueue, sgroup->splitter)))
Packit 971217
    goto splitter_link_failure;
Packit 971217
Packit 971217
  /* Expose input queue sink pad as ghostpad */
Packit 971217
  sinkpad = gst_element_get_static_pad (sgroup->inqueue, "sink");
Packit 971217
  if (sinkpadname == NULL) {
Packit 971217
    gchar *pname =
Packit 971217
        g_strdup_printf ("%s_%u", gst_encoding_profile_get_type_nick (sprof),
Packit 971217
        ebin->last_pad_id++);
Packit 971217
    GST_DEBUG ("Adding ghost pad %s", pname);
Packit 971217
    sgroup->ghostpad = gst_ghost_pad_new (pname, sinkpad);
Packit 971217
    g_free (pname);
Packit 971217
  } else
Packit 971217
    sgroup->ghostpad = gst_ghost_pad_new (sinkpadname, sinkpad);
Packit 971217
  gst_object_unref (sinkpad);
Packit 971217
Packit 971217
Packit 971217
  /* Path 1 : Already-encoded data */
Packit 971217
  sinkpad =
Packit 971217
      local_element_request_pad (sgroup->combiner, NULL, "passthroughsink",
Packit 971217
      NULL);
Packit 971217
  if (G_UNLIKELY (sinkpad == NULL))
Packit 971217
    goto no_combiner_sinkpad;
Packit 971217
Packit 971217
  if (ebin->avoid_reencoding) {
Packit 971217
    GstCaps *tmpcaps;
Packit 971217
Packit 971217
    GST_DEBUG ("Asked to use Smart Encoder");
Packit 971217
    sgroup->smartencoder = g_object_new (GST_TYPE_SMART_ENCODER, NULL);
Packit 971217
Packit 971217
    /* Check if stream format is compatible */
Packit 971217
    srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
Packit 971217
    tmpcaps = gst_pad_query_caps (srcpad, NULL);
Packit 971217
    if (!gst_caps_can_intersect (tmpcaps, format)) {
Packit 971217
      GST_DEBUG ("We don't have a smart encoder for the stream format");
Packit 971217
      gst_object_unref (sgroup->smartencoder);
Packit 971217
      sgroup->smartencoder = NULL;
Packit 971217
    } else {
Packit 971217
      gst_bin_add ((GstBin *) ebin, sgroup->smartencoder);
Packit 971217
      fast_pad_link (srcpad, sinkpad);
Packit 971217
      tosync = g_list_append (tosync, sgroup->smartencoder);
Packit 971217
      sinkpad = gst_element_get_static_pad (sgroup->smartencoder, "sink");
Packit 971217
    }
Packit 971217
    gst_caps_unref (tmpcaps);
Packit 971217
    g_object_unref (srcpad);
Packit 971217
  }
Packit 971217
Packit 971217
  srcpad =
Packit 971217
      local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc",
Packit 971217
      NULL);
Packit 971217
  if (G_UNLIKELY (srcpad == NULL))
Packit 971217
    goto no_splitter_srcpad;
Packit 971217
Packit 971217
  /* Go straight to splitter */
Packit 971217
  if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
Packit 971217
    goto passthrough_link_failure;
Packit 971217
  g_object_unref (sinkpad);
Packit 971217
  g_object_unref (srcpad);
Packit 971217
  srcpad = NULL;
Packit 971217
Packit 971217
  /* Path 2 : Conversion / Encoding */
Packit 971217
Packit 971217
  /* 1. Create the encoder */
Packit 971217
  GST_LOG ("Adding encoder");
Packit 971217
  sgroup->encoder = _get_encoder (ebin, sprof);
Packit 971217
  if (sgroup->encoder != NULL) {
Packit 971217
    gst_bin_add ((GstBin *) ebin, sgroup->encoder);
Packit 971217
    tosync = g_list_append (tosync, sgroup->encoder);
Packit 971217
Packit 971217
    sinkpad =
Packit 971217
        local_element_request_pad (sgroup->combiner, NULL, "encodingsink",
Packit 971217
        NULL);
Packit 971217
    if (G_UNLIKELY (sinkpad == NULL))
Packit 971217
      goto no_combiner_sinkpad;
Packit 971217
    srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
Packit 971217
    if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
Packit 971217
      goto encoder_link_failure;
Packit 971217
    g_object_unref (sinkpad);
Packit 971217
    g_object_unref (srcpad);
Packit 971217
    srcpad = NULL;
Packit 971217
  } else if (gst_encoding_profile_get_preset (sgroup->profile)
Packit 971217
      || gst_encoding_profile_get_preset_name (sgroup->profile)) {
Packit 971217
Packit 971217
    if (!encoder_not_found)
Packit 971217
      _post_missing_plugin_message (ebin, sprof);
Packit 971217
    else
Packit 971217
      *encoder_not_found = TRUE;
Packit 971217
    goto cleanup;
Packit 971217
  } else {
Packit 971217
    /* passthrough can still work, if we discover that *
Packit 971217
     * encoding is required we post a missing plugin message */
Packit 971217
  }
Packit 971217
Packit 971217
Packit 971217
  /* 3. Create the conversion/restriction elements */
Packit 971217
  /* 3.1. capsfilter */
Packit 971217
  GST_LOG ("Adding capsfilter for restriction caps : %" GST_PTR_FORMAT,
Packit 971217
      restriction);
Packit 971217
Packit 971217
  last = sgroup->capsfilter = gst_element_factory_make ("capsfilter", NULL);
Packit 971217
  if (restriction && !gst_caps_is_any (restriction))
Packit 971217
    g_object_set (sgroup->capsfilter, "caps", restriction, NULL);
Packit 971217
Packit 971217
  if (!gst_encoding_profile_get_allow_dynamic_output (sprof)) {
Packit 971217
    if (!sgroup->inputfilter_caps_sid) {
Packit 971217
      sgroup->inputfilter_caps_sid =
Packit 971217
          g_signal_connect (sgroup->capsfilter->sinkpads->data,
Packit 971217
          "notify::caps", G_CALLBACK (_capsfilter_force_format),
Packit 971217
          &sgroup->inputfilter_caps_sid);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  gst_bin_add ((GstBin *) ebin, sgroup->capsfilter);
Packit 971217
  tosync = g_list_append (tosync, sgroup->capsfilter);
Packit 971217
  if (sgroup->encoder == NULL) {
Packit 971217
    /* no encoder available but it might be possible to just do passthrough, so
Packit 971217
     * let's just set up a fake pad to detect that encoding was attempted and
Packit 971217
     * if so it posts the missing plugin message */
Packit 971217
    sgroup->fakesink = gst_element_factory_make ("fakesink", NULL);
Packit 971217
    g_object_set (sgroup->fakesink, "async", FALSE, NULL);
Packit 971217
    gst_bin_add (GST_BIN_CAST (ebin), sgroup->fakesink);
Packit 971217
    tosync = g_list_append (tosync, sgroup->fakesink);
Packit 971217
    encoder = sgroup->fakesink;
Packit 971217
Packit 971217
    _set_up_fake_encoder_pad_probe (ebin, sgroup);
Packit 971217
  } else {
Packit 971217
    encoder = sgroup->encoder;
Packit 971217
  }
Packit 971217
  fast_element_link (sgroup->capsfilter, encoder);
Packit 971217
  sgroup->restriction_sid = g_signal_connect (sprof, "notify::restriction-caps",
Packit 971217
      G_CALLBACK (_profile_restriction_caps_cb), sgroup);
Packit 971217
Packit 971217
  /* 3.2. restriction elements */
Packit 971217
  /* FIXME : Once we have properties for specific converters, use those */
Packit 971217
  if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
Packit 971217
    const gboolean native_video =
Packit 971217
        ! !(ebin->flags & GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION);
Packit 971217
    GstElement *cspace = NULL, *scale, *vrate, *cspace2 = NULL;
Packit 971217
Packit 971217
    GST_LOG ("Adding conversion elements for video stream");
Packit 971217
Packit 971217
    if (!native_video) {
Packit 971217
      cspace = gst_element_factory_make ("videoconvert", NULL);
Packit 971217
      scale = gst_element_factory_make ("videoscale", NULL);
Packit 971217
      if (!scale) {
Packit 971217
        missing_element_name = "videoscale";
Packit 971217
        goto missing_element;
Packit 971217
      }
Packit 971217
      /* 4-tap scaling and black borders */
Packit 971217
      g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
Packit 971217
      cspace2 = gst_element_factory_make ("videoconvert", NULL);
Packit 971217
Packit 971217
      if (!cspace || !cspace2) {
Packit 971217
        missing_element_name = "videoconvert";
Packit 971217
        goto missing_element;
Packit 971217
      }
Packit 971217
Packit 971217
      gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
Packit 971217
      tosync = g_list_append (tosync, cspace);
Packit 971217
      tosync = g_list_append (tosync, scale);
Packit 971217
      tosync = g_list_append (tosync, cspace2);
Packit 971217
Packit 971217
      sgroup->converters = g_list_prepend (sgroup->converters, cspace);
Packit 971217
      sgroup->converters = g_list_prepend (sgroup->converters, scale);
Packit 971217
      sgroup->converters = g_list_prepend (sgroup->converters, cspace2);
Packit 971217
Packit 971217
      if (!fast_element_link (cspace, scale) ||
Packit 971217
          !fast_element_link (scale, cspace2))
Packit 971217
        goto converter_link_failure;
Packit 971217
    }
Packit 971217
Packit 971217
    if (!gst_encoding_video_profile_get_variableframerate
Packit 971217
        (GST_ENCODING_VIDEO_PROFILE (sprof))) {
Packit 971217
      vrate = gst_element_factory_make ("videorate", NULL);
Packit 971217
      if (!vrate) {
Packit 971217
        missing_element_name = "videorate";
Packit 971217
        goto missing_element;
Packit 971217
      }
Packit 971217
      g_object_set (vrate, "skip-to-first", TRUE, NULL);
Packit 971217
Packit 971217
      gst_bin_add ((GstBin *) ebin, vrate);
Packit 971217
      tosync = g_list_prepend (tosync, vrate);
Packit 971217
      sgroup->converters = g_list_prepend (sgroup->converters, vrate);
Packit 971217
Packit 971217
      if ((!native_video && !fast_element_link (cspace2, vrate))
Packit 971217
          || !fast_element_link (vrate, last))
Packit 971217
        goto converter_link_failure;
Packit 971217
Packit 971217
      if (!native_video)
Packit 971217
        last = cspace;
Packit 971217
      else
Packit 971217
        last = vrate;
Packit 971217
    } else if (!native_video) {
Packit 971217
      if (!fast_element_link (cspace2, last))
Packit 971217
        goto converter_link_failure;
Packit 971217
      last = cspace;
Packit 971217
    }
Packit 971217
Packit 971217
  } else if (GST_IS_ENCODING_AUDIO_PROFILE (sprof)
Packit 971217
      && !(ebin->flags & GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION)) {
Packit 971217
    GstElement *aconv, *ares, *arate, *aconv2;
Packit 971217
Packit 971217
    GST_LOG ("Adding conversion elements for audio stream");
Packit 971217
Packit 971217
    arate = gst_element_factory_make ("audiorate", NULL);
Packit 971217
    if (!arate) {
Packit 971217
      missing_element_name = "audiorate";
Packit 971217
      goto missing_element;
Packit 971217
    }
Packit 971217
    g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
Packit 971217
    g_object_set (arate, "skip-to-first", TRUE, NULL);
Packit 971217
Packit 971217
    aconv = gst_element_factory_make ("audioconvert", NULL);
Packit 971217
    aconv2 = gst_element_factory_make ("audioconvert", NULL);
Packit 971217
    ares = gst_element_factory_make ("audioresample", NULL);
Packit 971217
    if (!aconv || !aconv2) {
Packit 971217
      missing_element_name = "audioconvert";
Packit 971217
      goto missing_element;
Packit 971217
    }
Packit 971217
    if (!ares) {
Packit 971217
      missing_element_name = "audioresample";
Packit 971217
      goto missing_element;
Packit 971217
    }
Packit 971217
Packit 971217
    gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
Packit 971217
    tosync = g_list_append (tosync, arate);
Packit 971217
    tosync = g_list_append (tosync, aconv);
Packit 971217
    tosync = g_list_append (tosync, ares);
Packit 971217
    tosync = g_list_append (tosync, aconv2);
Packit 971217
    if (!fast_element_link (arate, aconv) ||
Packit 971217
        !fast_element_link (aconv, ares) ||
Packit 971217
        !fast_element_link (ares, aconv2) || !fast_element_link (aconv2, last))
Packit 971217
      goto converter_link_failure;
Packit 971217
Packit 971217
    sgroup->converters = g_list_prepend (sgroup->converters, arate);
Packit 971217
    sgroup->converters = g_list_prepend (sgroup->converters, aconv);
Packit 971217
    sgroup->converters = g_list_prepend (sgroup->converters, ares);
Packit 971217
    sgroup->converters = g_list_prepend (sgroup->converters, aconv2);
Packit 971217
Packit 971217
    last = arate;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Link to stream splitter */
Packit 971217
  sinkpad = gst_element_get_static_pad (last, "sink");
Packit 971217
  srcpad =
Packit 971217
      local_element_request_pad (sgroup->splitter, NULL, "encodingsrc", NULL);
Packit 971217
  if (G_UNLIKELY (srcpad == NULL))
Packit 971217
    goto no_splitter_srcpad;
Packit 971217
  if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
Packit 971217
    goto splitter_encoding_failure;
Packit 971217
  g_object_unref (sinkpad);
Packit 971217
  g_object_unref (srcpad);
Packit 971217
  srcpad = NULL;
Packit 971217
Packit 971217
  /* End of Stream 2 setup */
Packit 971217
Packit 971217
  /* Sync all elements to parent state */
Packit 971217
  for (tmp = tosync; tmp; tmp = tmp->next)
Packit 971217
    gst_element_sync_state_with_parent ((GstElement *) tmp->data);
Packit 971217
  g_list_free (tosync);
Packit 971217
Packit 971217
  /* Add ghostpad */
Packit 971217
  GST_DEBUG ("Adding ghostpad %s:%s", GST_DEBUG_PAD_NAME (sgroup->ghostpad));
Packit 971217
  gst_pad_set_active (sgroup->ghostpad, TRUE);
Packit 971217
  gst_element_add_pad ((GstElement *) ebin, sgroup->ghostpad);
Packit 971217
Packit 971217
  /* Add StreamGroup to our list of streams */
Packit 971217
Packit 971217
  GST_DEBUG
Packit 971217
      ("Done creating elements, adding StreamGroup to our controlled stream list");
Packit 971217
Packit 971217
  ebin->streams = g_list_prepend (ebin->streams, sgroup);
Packit 971217
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
  if (restriction)
Packit 971217
    gst_caps_unref (restriction);
Packit 971217
Packit 971217
  return sgroup;
Packit 971217
Packit 971217
splitter_encoding_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
no_muxer_pad:
Packit 971217
  GST_ERROR_OBJECT (ebin,
Packit 971217
      "Couldn't find a compatible muxer pad to link encoder to");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
missing_element:
Packit 971217
  gst_element_post_message (GST_ELEMENT_CAST (ebin),
Packit 971217
      gst_missing_element_message_new (GST_ELEMENT_CAST (ebin),
Packit 971217
          missing_element_name));
Packit 971217
  GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
Packit 971217
      (_("Missing element '%s' - check your GStreamer installation."),
Packit 971217
          missing_element_name), (NULL));
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
encoder_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
muxer_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
formatter_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
outfilter_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin,
Packit 971217
      "Couldn't link output filter to output queue/formatter");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
passthrough_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
no_splitter_srcpad:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Couldn't get a source pad from the splitter");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
no_combiner_sinkpad:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Couldn't get a sink pad from the combiner");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
splitter_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failure linking to the splitter");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
combiner_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failure linking to the combiner");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
parser_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failure linking the parser");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
converter_link_failure:
Packit 971217
  GST_ERROR_OBJECT (ebin, "Failure linking the video converters");
Packit 971217
  goto cleanup;
Packit 971217
Packit 971217
cleanup:
Packit 971217
  /* FIXME : Actually properly cleanup everything */
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
  if (restriction)
Packit 971217
    gst_caps_unref (restriction);
Packit 971217
  if (srcpad)
Packit 971217
    gst_object_unref (srcpad);
Packit 971217
  stream_group_free (ebin, sgroup);
Packit 971217
  g_list_free (tosync);
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
Packit 971217
{
Packit 971217
  GstStructure *structure = data;
Packit 971217
  const GValue *other_value = gst_structure_id_get_value (structure, field_id);
Packit 971217
Packit 971217
  if (G_UNLIKELY (other_value == NULL))
Packit 971217
    return FALSE;
Packit 971217
  if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
/*
Packit 971217
 * checks that there is at least one structure on caps_a that has
Packit 971217
 * all its fields exactly the same as one structure on caps_b
Packit 971217
 */
Packit 971217
static gboolean
Packit 971217
_gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
Packit 971217
{
Packit 971217
  gint i, j;
Packit 971217
  gboolean res = FALSE;
Packit 971217
Packit 971217
  for (i = 0; i < gst_caps_get_size (caps_a); i++) {
Packit 971217
    GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
Packit 971217
    for (j = 0; j < gst_caps_get_size (caps_b); j++) {
Packit 971217
      GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
Packit 971217
Packit 971217
      res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
Packit 971217
          structure_b);
Packit 971217
      if (res)
Packit 971217
        goto end;
Packit 971217
    }
Packit 971217
  }
Packit 971217
end:
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
_factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
Packit 971217
    GstPadDirection dir, gboolean exact)
Packit 971217
{
Packit 971217
  const GList *templates;
Packit 971217
Packit 971217
  templates = gst_element_factory_get_static_pad_templates (factory);
Packit 971217
  while (templates) {
Packit 971217
    GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
Packit 971217
Packit 971217
    if (template->direction == dir) {
Packit 971217
      GstCaps *tmp = gst_static_caps_get (&template->static_caps);
Packit 971217
Packit 971217
      if ((exact && _gst_caps_match (caps, tmp)) ||
Packit 971217
          (!exact && gst_caps_can_intersect (tmp, caps))) {
Packit 971217
        gst_caps_unref (tmp);
Packit 971217
        return TRUE;
Packit 971217
      }
Packit 971217
      gst_caps_unref (tmp);
Packit 971217
    }
Packit 971217
    templates = g_list_next (templates);
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static inline GstElement *
Packit 971217
_get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof)
Packit 971217
{
Packit 971217
  GList *formatters, *tmpfmtr;
Packit 971217
  GstElement *formatter = NULL;
Packit 971217
  GstElementFactory *formatterfact = NULL;
Packit 971217
  GstCaps *format;
Packit 971217
  const gchar *preset, *preset_name;
Packit 971217
Packit 971217
  format = gst_encoding_profile_get_format (sprof);
Packit 971217
  preset = gst_encoding_profile_get_preset (sprof);
Packit 971217
  preset_name = gst_encoding_profile_get_preset_name (sprof);
Packit 971217
Packit 971217
  GST_DEBUG ("Getting list of formatters for format %" GST_PTR_FORMAT, format);
Packit 971217
Packit 971217
  formatters =
Packit 971217
      gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
Packit 971217
      FALSE);
Packit 971217
Packit 971217
  if (formatters == NULL)
Packit 971217
    goto beach;
Packit 971217
Packit 971217
  /* FIXME : signal the user if he wants this */
Packit 971217
  for (tmpfmtr = formatters; tmpfmtr; tmpfmtr = tmpfmtr->next) {
Packit 971217
    formatterfact = (GstElementFactory *) tmpfmtr->data;
Packit 971217
Packit 971217
    GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
Packit 971217
        GST_OBJECT_NAME (formatterfact));
Packit 971217
Packit 971217
    if ((formatter =
Packit 971217
            _create_element_and_set_preset (formatterfact, preset,
Packit 971217
                NULL, preset_name)))
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_plugin_feature_list_free (formatters);
Packit 971217
Packit 971217
beach:
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
  return formatter;
Packit 971217
}
Packit 971217
Packit 971217
static gint
Packit 971217
compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
Packit 971217
{
Packit 971217
  GstCaps *caps = udata;
Packit 971217
  GstElementFactory *fac_a = (GstElementFactory *) a;
Packit 971217
  GstElementFactory *fac_b = (GstElementFactory *) b;
Packit 971217
Packit 971217
  /* FIXME not quite sure this is the best algorithm to order the elements
Packit 971217
   * Some caps similarity comparison algorithm would fit better than going
Packit 971217
   * boolean (equals/not equals).
Packit 971217
   */
Packit 971217
  gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
Packit 971217
  gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
Packit 971217
Packit 971217
  if (equals_a == equals_b) {
Packit 971217
    return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
Packit 971217
        gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
Packit 971217
  } else if (equals_a) {
Packit 971217
    return -1;
Packit 971217
  } else if (equals_b) {
Packit 971217
    return 1;
Packit 971217
  }
Packit 971217
  return 0;
Packit 971217
}
Packit 971217
Packit 971217
static inline GstElement *
Packit 971217
_get_muxer (GstEncodeBin * ebin)
Packit 971217
{
Packit 971217
  GList *muxers, *formatters, *tmpmux;
Packit 971217
  GstElement *muxer = NULL;
Packit 971217
  GstElementFactory *muxerfact = NULL;
Packit 971217
  const GList *tmp;
Packit 971217
  GstCaps *format;
Packit 971217
  const gchar *preset, *preset_name;
Packit 971217
Packit 971217
  format = gst_encoding_profile_get_format (ebin->profile);
Packit 971217
  preset = gst_encoding_profile_get_preset (ebin->profile);
Packit 971217
  preset_name = gst_encoding_profile_get_preset_name (ebin->profile);
Packit 971217
Packit 971217
  GST_DEBUG ("Getting list of muxers for format %" GST_PTR_FORMAT, format);
Packit 971217
Packit 971217
  muxers =
Packit 971217
      gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
Packit 971217
Packit 971217
  formatters =
Packit 971217
      gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
Packit 971217
      TRUE);
Packit 971217
Packit 971217
  muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
Packit 971217
  formatters =
Packit 971217
      g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
Packit 971217
Packit 971217
  muxers = g_list_concat (muxers, formatters);
Packit 971217
Packit 971217
  if (muxers == NULL)
Packit 971217
    goto beach;
Packit 971217
Packit 971217
  /* FIXME : signal the user if he wants this */
Packit 971217
  for (tmpmux = muxers; tmpmux; tmpmux = tmpmux->next) {
Packit 971217
    gboolean cansinkstreams = TRUE;
Packit 971217
    const GList *profiles =
Packit 971217
        gst_encoding_container_profile_get_profiles
Packit 971217
        (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
Packit 971217
Packit 971217
    muxerfact = (GstElementFactory *) tmpmux->data;
Packit 971217
Packit 971217
    GST_DEBUG ("Trying muxer %s", GST_OBJECT_NAME (muxerfact));
Packit 971217
Packit 971217
    /* See if the muxer can sink all of our stream profile caps */
Packit 971217
    for (tmp = profiles; tmp; tmp = tmp->next) {
Packit 971217
      GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
Packit 971217
      GstCaps *sformat = gst_encoding_profile_get_format (sprof);
Packit 971217
Packit 971217
      if (!_factory_can_handle_caps (muxerfact, sformat, GST_PAD_SINK, FALSE)) {
Packit 971217
        GST_DEBUG ("Skipping muxer because it can't sink caps %"
Packit 971217
            GST_PTR_FORMAT, sformat);
Packit 971217
        cansinkstreams = FALSE;
Packit 971217
        if (sformat)
Packit 971217
          gst_caps_unref (sformat);
Packit 971217
        break;
Packit 971217
      }
Packit 971217
      if (sformat)
Packit 971217
        gst_caps_unref (sformat);
Packit 971217
    }
Packit 971217
Packit 971217
    /* Only use a muxer than can use all streams and than can accept the
Packit 971217
     * preset (which may be present or not) */
Packit 971217
    if (cansinkstreams && (muxer =
Packit 971217
            _create_element_and_set_preset (muxerfact, preset, "muxer",
Packit 971217
                preset_name)))
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  gst_plugin_feature_list_free (muxers);
Packit 971217
Packit 971217
beach:
Packit 971217
  if (format)
Packit 971217
    gst_caps_unref (format);
Packit 971217
  return muxer;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
create_elements_and_pads (GstEncodeBin * ebin)
Packit 971217
{
Packit 971217
  gboolean ret = TRUE;
Packit 971217
  GstElement *muxer = NULL;
Packit 971217
  GstPad *muxerpad;
Packit 971217
  const GList *tmp, *profiles;
Packit 971217
  GstEncodingProfile *sprof;
Packit 971217
Packit 971217
  GST_DEBUG ("Current profile : %s",
Packit 971217
      gst_encoding_profile_get_name (ebin->profile));
Packit 971217
Packit 971217
  if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
Packit 971217
    /* 1. Get the compatible muxer */
Packit 971217
    muxer = _get_muxer (ebin);
Packit 971217
    if (G_UNLIKELY (muxer == NULL))
Packit 971217
      goto no_muxer;
Packit 971217
Packit 971217
    /* Record the muxer */
Packit 971217
    ebin->muxer = muxer;
Packit 971217
    gst_bin_add ((GstBin *) ebin, muxer);
Packit 971217
Packit 971217
    /* 2. Ghost the muxer source pad */
Packit 971217
Packit 971217
    /* FIXME : We should figure out if it's a static/request/dyamic pad,
Packit 971217
     * but for the time being let's assume it's a static pad :) */
Packit 971217
    muxerpad = gst_element_get_static_pad (muxer, "src");
Packit 971217
    if (G_UNLIKELY (muxerpad == NULL))
Packit 971217
      goto no_muxer_pad;
Packit 971217
Packit 971217
    if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad))
Packit 971217
      goto no_muxer_ghost_pad;
Packit 971217
Packit 971217
    gst_object_unref (muxerpad);
Packit 971217
    /* 3. Activate fixed presence streams */
Packit 971217
    profiles =
Packit 971217
        gst_encoding_container_profile_get_profiles
Packit 971217
        (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
Packit 971217
    for (tmp = profiles; tmp; tmp = tmp->next) {
Packit 971217
      sprof = (GstEncodingProfile *) tmp->data;
Packit 971217
Packit 971217
      GST_DEBUG ("Trying stream profile with presence %d",
Packit 971217
          gst_encoding_profile_get_presence (sprof));
Packit 971217
Packit 971217
      if (gst_encoding_profile_get_presence (sprof) != 0 &&
Packit 971217
          gst_encoding_profile_is_enabled (sprof)) {
Packit 971217
        if (G_UNLIKELY (_create_stream_group (ebin, sprof, NULL, NULL,
Packit 971217
                    NULL) == NULL))
Packit 971217
          goto stream_error;
Packit 971217
      }
Packit 971217
    }
Packit 971217
    gst_element_sync_state_with_parent (muxer);
Packit 971217
  } else {
Packit 971217
    if (G_UNLIKELY (_create_stream_group (ebin, ebin->profile, NULL,
Packit 971217
                NULL, NULL) == NULL))
Packit 971217
      goto stream_error;
Packit 971217
  }
Packit 971217
Packit 971217
  return ret;
Packit 971217
Packit 971217
no_muxer:
Packit 971217
  {
Packit 971217
    GstCaps *format = gst_encoding_profile_get_format (ebin->profile);
Packit 971217
Packit 971217
    GST_WARNING ("No available muxer for %" GST_PTR_FORMAT, format);
Packit 971217
    /* missing plugin support */
Packit 971217
    gst_element_post_message (GST_ELEMENT_CAST (ebin),
Packit 971217
        gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
Packit 971217
    GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
Packit 971217
        ("No available muxer for format %" GST_PTR_FORMAT, format));
Packit 971217
    if (format)
Packit 971217
      gst_caps_unref (format);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
no_muxer_pad:
Packit 971217
  {
Packit 971217
    GST_WARNING ("Can't get source pad from muxer (%s)",
Packit 971217
        GST_ELEMENT_NAME (muxer));
Packit 971217
    gst_bin_remove (GST_BIN (ebin), muxer);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
no_muxer_ghost_pad:
Packit 971217
  {
Packit 971217
    GST_WARNING ("Couldn't set %s:%s as source ghostpad target",
Packit 971217
        GST_DEBUG_PAD_NAME (muxerpad));
Packit 971217
    gst_bin_remove (GST_BIN (ebin), muxer);
Packit 971217
    gst_object_unref (muxerpad);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
stream_error:
Packit 971217
  {
Packit 971217
    GST_WARNING ("Could not create Streams");
Packit 971217
    if (muxer)
Packit 971217
      gst_bin_remove (GST_BIN (ebin), muxer);
Packit 971217
    ebin->muxer = NULL;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
release_pads (const GValue * item, GstElement * elt)
Packit 971217
{
Packit 971217
  GstPad *pad = g_value_get_object (item);
Packit 971217
  GstPad *peer = NULL;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
Packit 971217
Packit 971217
  /* Unlink from its peer pad */
Packit 971217
  if ((peer = gst_pad_get_peer (pad))) {
Packit 971217
    if (GST_PAD_DIRECTION (peer) == GST_PAD_SRC)
Packit 971217
      gst_pad_unlink (peer, pad);
Packit 971217
    else
Packit 971217
      gst_pad_unlink (pad, peer);
Packit 971217
    gst_object_unref (peer);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Release it from the object */
Packit 971217
  gst_element_release_request_pad (elt, pad);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
  GstPad *tmppad;
Packit 971217
  GstPad *pad;
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (ebin, "Freeing StreamGroup %p", sgroup);
Packit 971217
Packit 971217
  if (sgroup->restriction_sid != 0)
Packit 971217
    g_signal_handler_disconnect (sgroup->profile, sgroup->restriction_sid);
Packit 971217
Packit 971217
  if (sgroup->outqueue) {
Packit 971217
    if (ebin->muxer) {
Packit 971217
      /* outqueue - Muxer */
Packit 971217
      tmppad = gst_element_get_static_pad (sgroup->outqueue, "src");
Packit 971217
      pad = gst_pad_get_peer (tmppad);
Packit 971217
Packit 971217
      if (pad) {
Packit 971217
        /* Remove muxer request sink pad */
Packit 971217
        gst_pad_unlink (tmppad, pad);
Packit 971217
        if (GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) ==
Packit 971217
            GST_PAD_REQUEST)
Packit 971217
          gst_element_release_request_pad (ebin->muxer, pad);
Packit 971217
        gst_object_unref (pad);
Packit 971217
      }
Packit 971217
      gst_object_unref (tmppad);
Packit 971217
    }
Packit 971217
    gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
Packit 971217
  }
Packit 971217
Packit 971217
  if (sgroup->formatter) {
Packit 971217
    /* capsfilter - formatter - outqueue */
Packit 971217
    gst_element_set_state (sgroup->formatter, GST_STATE_NULL);
Packit 971217
    gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
Packit 971217
    gst_element_unlink (sgroup->formatter, sgroup->outqueue);
Packit 971217
    gst_element_unlink (sgroup->outfilter, sgroup->formatter);
Packit 971217
  } else if (sgroup->outfilter) {
Packit 971217
    /* Capsfilter - outqueue */
Packit 971217
    gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
Packit 971217
    gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
Packit 971217
  }
Packit 971217
Packit 971217
  if (sgroup->outqueue) {
Packit 971217
    gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
Packit 971217
    gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);
Packit 971217
  }
Packit 971217
Packit 971217
  /* streamcombiner - parser - capsfilter */
Packit 971217
  if (sgroup->parser) {
Packit 971217
    gst_element_set_state (sgroup->parser, GST_STATE_NULL);
Packit 971217
    gst_element_unlink (sgroup->parser, sgroup->outfilter);
Packit 971217
    gst_element_unlink (sgroup->combiner, sgroup->parser);
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->parser);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Sink Ghostpad */
Packit 971217
  if (sgroup->ghostpad) {
Packit 971217
    if (GST_PAD_PARENT (sgroup->ghostpad) != NULL)
Packit 971217
      gst_element_remove_pad (GST_ELEMENT_CAST (ebin), sgroup->ghostpad);
Packit 971217
    else
Packit 971217
      gst_object_unref (sgroup->ghostpad);
Packit 971217
  }
Packit 971217
Packit 971217
  if (sgroup->inqueue)
Packit 971217
    gst_element_set_state (sgroup->inqueue, GST_STATE_NULL);
Packit 971217
Packit 971217
  if (sgroup->encoder)
Packit 971217
    gst_element_set_state (sgroup->encoder, GST_STATE_NULL);
Packit 971217
  if (sgroup->fakesink)
Packit 971217
    gst_element_set_state (sgroup->fakesink, GST_STATE_NULL);
Packit 971217
  if (sgroup->outfilter) {
Packit 971217
    gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
Packit 971217
Packit 971217
    if (sgroup->outputfilter_caps_sid) {
Packit 971217
      g_signal_handler_disconnect (sgroup->outfilter->sinkpads->data,
Packit 971217
          sgroup->outputfilter_caps_sid);
Packit 971217
      sgroup->outputfilter_caps_sid = 0;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  if (sgroup->smartencoder)
Packit 971217
    gst_element_set_state (sgroup->smartencoder, GST_STATE_NULL);
Packit 971217
Packit 971217
  if (sgroup->capsfilter) {
Packit 971217
    gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL);
Packit 971217
    if (sgroup->encoder)
Packit 971217
      gst_element_unlink (sgroup->capsfilter, sgroup->encoder);
Packit 971217
    else
Packit 971217
      gst_element_unlink (sgroup->capsfilter, sgroup->fakesink);
Packit 971217
Packit 971217
    if (sgroup->inputfilter_caps_sid) {
Packit 971217
      g_signal_handler_disconnect (sgroup->capsfilter->sinkpads->data,
Packit 971217
          sgroup->inputfilter_caps_sid);
Packit 971217
      sgroup->inputfilter_caps_sid = 0;
Packit 971217
    }
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter);
Packit 971217
  }
Packit 971217
Packit 971217
  for (tmp = sgroup->converters; tmp; tmp = tmp->next) {
Packit 971217
    GstElement *elt = (GstElement *) tmp->data;
Packit 971217
Packit 971217
    gst_element_set_state (elt, GST_STATE_NULL);
Packit 971217
    gst_bin_remove ((GstBin *) ebin, elt);
Packit 971217
  }
Packit 971217
  if (sgroup->converters)
Packit 971217
    g_list_free (sgroup->converters);
Packit 971217
Packit 971217
  if (sgroup->combiner) {
Packit 971217
    GstIterator *it = gst_element_iterate_sink_pads (sgroup->combiner);
Packit 971217
    GstIteratorResult itret = GST_ITERATOR_OK;
Packit 971217
Packit 971217
    while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
Packit 971217
      itret =
Packit 971217
          gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
Packit 971217
          sgroup->combiner);
Packit 971217
      gst_iterator_resync (it);
Packit 971217
    }
Packit 971217
    gst_iterator_free (it);
Packit 971217
    gst_element_set_state (sgroup->combiner, GST_STATE_NULL);
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->combiner);
Packit 971217
  }
Packit 971217
Packit 971217
  if (sgroup->splitter) {
Packit 971217
    GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
Packit 971217
    GstIteratorResult itret = GST_ITERATOR_OK;
Packit 971217
    while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
Packit 971217
      itret =
Packit 971217
          gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
Packit 971217
          sgroup->splitter);
Packit 971217
      gst_iterator_resync (it);
Packit 971217
    }
Packit 971217
    gst_iterator_free (it);
Packit 971217
Packit 971217
    gst_element_set_state (sgroup->splitter, GST_STATE_NULL);
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->splitter);
Packit 971217
  }
Packit 971217
Packit 971217
  if (sgroup->inqueue)
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->inqueue);
Packit 971217
Packit 971217
  if (sgroup->encoder)
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->encoder);
Packit 971217
Packit 971217
  if (sgroup->fakesink)
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->fakesink);
Packit 971217
Packit 971217
  if (sgroup->smartencoder)
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder);
Packit 971217
Packit 971217
  if (sgroup->outfilter)
Packit 971217
    gst_bin_remove ((GstBin *) ebin, sgroup->outfilter);
Packit 971217
Packit 971217
  g_slice_free (StreamGroup, sgroup);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup)
Packit 971217
{
Packit 971217
  ebin->streams = g_list_remove (ebin->streams, sgroup);
Packit 971217
Packit 971217
  stream_group_free (ebin, sgroup);
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_tear_down_profile (GstEncodeBin * ebin)
Packit 971217
{
Packit 971217
  if (G_UNLIKELY (ebin->profile == NULL))
Packit 971217
    return;
Packit 971217
Packit 971217
  GST_DEBUG ("Tearing down profile %s",
Packit 971217
      gst_encoding_profile_get_name (ebin->profile));
Packit 971217
Packit 971217
  while (ebin->streams)
Packit 971217
    stream_group_remove (ebin, (StreamGroup *) ebin->streams->data);
Packit 971217
Packit 971217
  /* Set ghostpad target to NULL */
Packit 971217
  gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), NULL);
Packit 971217
Packit 971217
  /* Remove muxer if present */
Packit 971217
  if (ebin->muxer) {
Packit 971217
    gst_element_set_state (ebin->muxer, GST_STATE_NULL);
Packit 971217
    gst_bin_remove (GST_BIN (ebin), ebin->muxer);
Packit 971217
    ebin->muxer = NULL;
Packit 971217
  }
Packit 971217
Packit 971217
  /* free/clear profile */
Packit 971217
  gst_encoding_profile_unref (ebin->profile);
Packit 971217
  ebin->profile = NULL;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_encode_bin_setup_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
Packit 971217
{
Packit 971217
  gboolean res;
Packit 971217
Packit 971217
  g_return_val_if_fail (ebin->profile == NULL, FALSE);
Packit 971217
Packit 971217
  GST_DEBUG ("Setting up profile %p:%s (type:%s)", profile,
Packit 971217
      gst_encoding_profile_get_name (profile),
Packit 971217
      gst_encoding_profile_get_type_nick (profile));
Packit 971217
Packit 971217
  ebin->profile = profile;
Packit 971217
  gst_object_ref (ebin->profile);
Packit 971217
Packit 971217
  /* Create elements */
Packit 971217
  res = create_elements_and_pads (ebin);
Packit 971217
  if (!res)
Packit 971217
    gst_encode_bin_tear_down_profile (ebin);
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
Packit 971217
Packit 971217
  GST_DEBUG_OBJECT (ebin, "profile (%p) : %s", profile,
Packit 971217
      gst_encoding_profile_get_name (profile));
Packit 971217
Packit 971217
  if (G_UNLIKELY (ebin->active)) {
Packit 971217
    GST_WARNING_OBJECT (ebin, "Element already active, can't change profile");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
Packit 971217
  /* If we're not active, we can deactivate the previous profile */
Packit 971217
  if (ebin->profile) {
Packit 971217
    gst_encode_bin_tear_down_profile (ebin);
Packit 971217
  }
Packit 971217
Packit 971217
  return gst_encode_bin_setup_profile (ebin, profile);
Packit 971217
}
Packit 971217
Packit 971217
static inline gboolean
Packit 971217
gst_encode_bin_activate (GstEncodeBin * ebin)
Packit 971217
{
Packit 971217
  ebin->active = ebin->profile != NULL;
Packit 971217
  return ebin->active;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_encode_bin_deactivate (GstEncodeBin * ebin)
Packit 971217
{
Packit 971217
  GList *tmp;
Packit 971217
Packit 971217
  for (tmp = ebin->streams; tmp; tmp = tmp->next) {
Packit 971217
    StreamGroup *sgroup = tmp->data;
Packit 971217
    GstCaps *format = gst_encoding_profile_get_format (sgroup->profile);
Packit 971217
Packit 971217
    _set_group_caps_format (sgroup, sgroup->profile, format);
Packit 971217
Packit 971217
    if (format)
Packit 971217
      gst_caps_unref (format);
Packit 971217
  }
Packit 971217
Packit 971217
  ebin->active = FALSE;
Packit 971217
}
Packit 971217
Packit 971217
static GstStateChangeReturn
Packit 971217
gst_encode_bin_change_state (GstElement * element, GstStateChange transition)
Packit 971217
{
Packit 971217
  GstStateChangeReturn ret;
Packit 971217
  GstEncodeBin *ebin = (GstEncodeBin *) element;
Packit 971217
Packit 971217
  switch (transition) {
Packit 971217
    case GST_STATE_CHANGE_READY_TO_PAUSED:
Packit 971217
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
Packit 971217
      if (!gst_encode_bin_activate (ebin)) {
Packit 971217
        ret = GST_STATE_CHANGE_FAILURE;
Packit 971217
        goto beach;
Packit 971217
      }
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  ret =
Packit 971217
      GST_ELEMENT_CLASS (gst_encode_bin_parent_class)->change_state (element,
Packit 971217
      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
      gst_encode_bin_deactivate (ebin);
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
beach:
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
static gboolean
Packit 971217
plugin_init (GstPlugin * plugin)
Packit 971217
{
Packit 971217
  gboolean res;
Packit 971217
Packit 971217
  GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin");
Packit 971217
Packit 971217
#ifdef ENABLE_NLS
Packit 971217
  GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
Packit 971217
      LOCALEDIR);
Packit 971217
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
Packit 971217
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Packit 971217
#endif /* ENABLE_NLS */
Packit 971217
Packit 971217
Packit 971217
  res = gst_element_register (plugin, "encodebin", GST_RANK_NONE,
Packit 971217
      GST_TYPE_ENCODE_BIN);
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
Packit 971217
    GST_VERSION_MINOR,
Packit 971217
    encoding,
Packit 971217
    "various encoding-related elements", plugin_init, VERSION, GST_LICENSE,
Packit 971217
    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)