gst-gmyth/decodebin2/gstdecodebin2.c
author renatofilho
Tue Jul 17 23:17:09 2007 +0100 (2007-07-17)
branchtrunk
changeset 788 357b301e2d23
child 792 a6ac25bf88a7
permissions -rw-r--r--
[svn r794] -fixed volume property for audio sinks elements; - Created property parse-metadata for enable parse files metadata
renatofilho@787
     1
/* GStreamer
renatofilho@787
     2
 * Copyright (C) <2006> Edward Hervey <edward@fluendo.com>
renatofilho@787
     3
 *
renatofilho@787
     4
 * This library is free software; you can redistribute it and/or
renatofilho@787
     5
 * modify it under the terms of the GNU Library General Public
renatofilho@787
     6
 * License as published by the Free Software Foundation; either
renatofilho@787
     7
 * version 2 of the License, or (at your option) any later version.
renatofilho@787
     8
 *
renatofilho@787
     9
 * This library is distributed in the hope that it will be useful,
renatofilho@787
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
renatofilho@787
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
renatofilho@787
    12
 * Library General Public License for more details.
renatofilho@787
    13
 *
renatofilho@787
    14
 * You should have received a copy of the GNU Library General Public
renatofilho@787
    15
 * License along with this library; if not, write to the
renatofilho@787
    16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
renatofilho@787
    17
 * Boston, MA 02111-1307, USA.
renatofilho@787
    18
 */
renatofilho@787
    19
renatofilho@787
    20
/**
renatofilho@787
    21
 * SECTION:element-decodebin2
renatofilho@787
    22
 * @short_description: Next-generation automatic decoding bin
renatofilho@787
    23
 *
renatofilho@787
    24
 * #GstBin that auto-magically constructs a decoding pipeline using available
renatofilho@787
    25
 * decoders and demuxers via auto-plugging.
renatofilho@787
    26
 *
renatofilho@787
    27
 * At this stage, decodebin2 is considered UNSTABLE. The API provided in the
renatofilho@787
    28
 * signals is expected to change in the near future. 
renatofilho@787
    29
 *
renatofilho@787
    30
 * To try out decodebin2, you can set the USE_DECODEBIN2 environment 
renatofilho@787
    31
 * variable (USE_DECODEBIN2=1 for example). This will cause playbin to use
renatofilho@787
    32
 * decodebin2 instead of the older decodebin for its internal auto-plugging.
renatofilho@787
    33
 */
renatofilho@787
    34
renatofilho@787
    35
#ifdef HAVE_CONFIG_H
renatofilho@787
    36
#include "config.h"
renatofilho@787
    37
#endif
renatofilho@787
    38
renatofilho@787
    39
#include <string.h>
renatofilho@787
    40
#include <gst/gst.h>
renatofilho@787
    41
renatofilho@787
    42
#include "gstplay-marshal.h"
renatofilho@787
    43
renatofilho@787
    44
/* generic templates */
renatofilho@787
    45
static GstStaticPadTemplate decoder_bin_sink_template =
renatofilho@787
    46
GST_STATIC_PAD_TEMPLATE ("sink",
renatofilho@787
    47
    GST_PAD_SINK,
renatofilho@787
    48
    GST_PAD_ALWAYS,
renatofilho@787
    49
    GST_STATIC_CAPS_ANY);
renatofilho@787
    50
renatofilho@787
    51
static GstStaticPadTemplate decoder_bin_src_template =
renatofilho@787
    52
GST_STATIC_PAD_TEMPLATE ("src%d",
renatofilho@787
    53
    GST_PAD_SRC,
renatofilho@787
    54
    GST_PAD_SOMETIMES,
renatofilho@787
    55
    GST_STATIC_CAPS_ANY);
renatofilho@787
    56
renatofilho@787
    57
GST_DEBUG_CATEGORY_STATIC (gst_decode_bin_debug);
renatofilho@787
    58
#define GST_CAT_DEFAULT gst_decode_bin_debug
renatofilho@787
    59
renatofilho@787
    60
typedef struct _GstDecodeGroup GstDecodeGroup;
renatofilho@787
    61
typedef struct _GstDecodePad GstDecodePad;
renatofilho@787
    62
typedef struct _GstDecodeBin GstDecodeBin;
renatofilho@787
    63
typedef struct _GstDecodeBin GstDecodeBin2;
renatofilho@787
    64
typedef struct _GstDecodeBinClass GstDecodeBinClass;
renatofilho@787
    65
renatofilho@787
    66
#define GST_TYPE_DECODE_BIN             (gst_decode_bin_get_type())
renatofilho@787
    67
#define GST_DECODE_BIN_CAST(obj)        ((GstDecodeBin*)(obj))
renatofilho@787
    68
#define GST_DECODE_BIN(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DECODE_BIN,GstDecodeBin))
renatofilho@787
    69
#define GST_DECODE_BIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DECODE_BIN,GstDecodeBinClass))
renatofilho@787
    70
#define GST_IS_DECODE_BIN(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DECODE_BIN))
renatofilho@787
    71
#define GST_IS_DECODE_BIN_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DECODE_BIN))
renatofilho@787
    72
renatofilho@787
    73
/**
renatofilho@787
    74
 *  GstDecodeBin2:
renatofilho@787
    75
 *
renatofilho@787
    76
 *  The opaque #DecodeBin2 data structure
renatofilho@787
    77
 */
renatofilho@787
    78
struct _GstDecodeBin
renatofilho@787
    79
{
renatofilho@787
    80
  GstBin bin;                   /* we extend GstBin */
renatofilho@787
    81
renatofilho@787
    82
  GstElement *typefind;         /* this holds the typefind object */
renatofilho@787
    83
  GstElement *fakesink;
renatofilho@787
    84
renatofilho@787
    85
  GMutex *lock;                 /* Protects activegroup and groups */
renatofilho@787
    86
  GstDecodeGroup *activegroup;  /* group currently active */
renatofilho@787
    87
  GList *groups;                /* List of non-active GstDecodeGroups, sorted in
renatofilho@787
    88
                                 * order of creation. */
renatofilho@787
    89
  GList *oldgroups;             /* List of no-longer-used GstDecodeGroups. 
renatofilho@787
    90
                                 * Should be freed in dispose */
renatofilho@787
    91
  gint nbpads;                  /* unique identifier for source pads */
renatofilho@787
    92
  GstCaps *caps;                /* caps on which to stop decoding */
renatofilho@787
    93
renatofilho@787
    94
  GList *factories;             /* factories we can use for selecting elements */
renatofilho@787
    95
};
renatofilho@787
    96
renatofilho@787
    97
struct _GstDecodeBinClass
renatofilho@787
    98
{
renatofilho@787
    99
  GstBinClass parent_class;
renatofilho@787
   100
renatofilho@787
   101
  /* signal we fire when a new pad has been decoded into raw audio/video */
renatofilho@787
   102
  void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
renatofilho@787
   103
  /* signal we fire when a pad has been removed */
renatofilho@787
   104
  void (*removed_decoded_pad) (GstElement * element, GstPad * pad);
renatofilho@787
   105
  /* signal fired when we found a pad that we cannot decode */
renatofilho@787
   106
  void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
renatofilho@787
   107
  /* signal fired to know if we continue trying to decode the given caps */
renatofilho@787
   108
    gboolean (*autoplug_continue) (GstElement * element, GstCaps * caps);
renatofilho@787
   109
  /* signal fired to reorder the proposed list of factories */
renatofilho@787
   110
    gboolean (*autoplug_sort) (GstElement * element, GstCaps * caps,
renatofilho@787
   111
      GList ** list);
renatofilho@787
   112
};
renatofilho@787
   113
renatofilho@787
   114
/* signals */
renatofilho@787
   115
enum
renatofilho@787
   116
{
renatofilho@787
   117
  SIGNAL_NEW_DECODED_PAD,
renatofilho@787
   118
  SIGNAL_REMOVED_DECODED_PAD,
renatofilho@787
   119
  SIGNAL_UNKNOWN_TYPE,
renatofilho@787
   120
  SIGNAL_AUTOPLUG_CONTINUE,
renatofilho@787
   121
  SIGNAL_AUTOPLUG_SORT,
renatofilho@787
   122
  LAST_SIGNAL
renatofilho@787
   123
};
renatofilho@787
   124
renatofilho@787
   125
/* Properties */
renatofilho@787
   126
enum
renatofilho@787
   127
{
renatofilho@787
   128
  PROP_0,
renatofilho@787
   129
  PROP_CAPS,
renatofilho@787
   130
};
renatofilho@787
   131
renatofilho@787
   132
static GstBinClass *parent_class;
renatofilho@787
   133
static guint gst_decode_bin_signals[LAST_SIGNAL] = { 0 };
renatofilho@787
   134
renatofilho@787
   135
static const GstElementDetails gst_decode_bin_details =
renatofilho@787
   136
GST_ELEMENT_DETAILS ("Decoder Bin",
renatofilho@787
   137
    "Generic/Bin/Decoder",
renatofilho@787
   138
    "Autoplug and decode to raw media",
renatofilho@787
   139
    "Edward Hervey <edward@fluendo.com>");
renatofilho@787
   140
renatofilho@787
   141
renatofilho@787
   142
static gboolean add_fakesink (GstDecodeBin * decode_bin);
renatofilho@787
   143
static void remove_fakesink (GstDecodeBin * decode_bin);
renatofilho@787
   144
renatofilho@787
   145
static void type_found (GstElement * typefind, guint probability,
renatofilho@787
   146
    GstCaps * caps, GstDecodeBin * decode_bin);
renatofilho@787
   147
renatofilho@787
   148
static gboolean gst_decode_bin_autoplug_continue (GstElement * element,
renatofilho@787
   149
    GstCaps * caps);
renatofilho@787
   150
static gboolean gst_decode_bin_autoplug_sort (GstElement * element,
renatofilho@787
   151
    GstCaps * caps, GList ** list);
renatofilho@787
   152
static void gst_decode_bin_set_property (GObject * object, guint prop_id,
renatofilho@787
   153
    const GValue * value, GParamSpec * pspec);
renatofilho@787
   154
static void gst_decode_bin_get_property (GObject * object, guint prop_id,
renatofilho@787
   155
    GValue * value, GParamSpec * pspec);
renatofilho@787
   156
static void gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps);
renatofilho@787
   157
static GstCaps *gst_decode_bin_get_caps (GstDecodeBin * dbin);
renatofilho@787
   158
renatofilho@787
   159
static GstPad *find_sink_pad (GstElement * element);
renatofilho@787
   160
static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
renatofilho@787
   161
    GstStateChange transition);
renatofilho@787
   162
renatofilho@787
   163
#define DECODE_BIN_LOCK(dbin) G_STMT_START {				\
renatofilho@787
   164
    GST_LOG_OBJECT (dbin,						\
renatofilho@787
   165
		    "locking from thread %p",				\
renatofilho@787
   166
		    g_thread_self ());					\
renatofilho@787
   167
    g_mutex_lock (GST_DECODE_BIN_CAST(dbin)->lock);			\
renatofilho@787
   168
    GST_LOG_OBJECT (dbin,						\
renatofilho@787
   169
		    "locked from thread %p",				\
renatofilho@787
   170
		    g_thread_self ());					\
renatofilho@787
   171
} G_STMT_END
renatofilho@787
   172
renatofilho@787
   173
#define DECODE_BIN_UNLOCK(dbin) G_STMT_START {				\
renatofilho@787
   174
    GST_LOG_OBJECT (dbin,						\
renatofilho@787
   175
		    "unlocking from thread %p",				\
renatofilho@787
   176
		    g_thread_self ());					\
renatofilho@787
   177
    g_mutex_unlock (GST_DECODE_BIN_CAST(dbin)->lock);			\
renatofilho@787
   178
} G_STMT_END
renatofilho@787
   179
renatofilho@787
   180
/* GstDecodeGroup
renatofilho@787
   181
 *
renatofilho@787
   182
 * Streams belonging to the same group/chain of a media file
renatofilho@787
   183
 *
renatofilho@787
   184
 */
renatofilho@787
   185
renatofilho@787
   186
struct _GstDecodeGroup
renatofilho@787
   187
{
renatofilho@787
   188
  GstDecodeBin *dbin;
renatofilho@787
   189
  GMutex *lock;
renatofilho@787
   190
  GstElement *multiqueue;
renatofilho@787
   191
  gboolean exposed;             /* TRUE if this group is exposed */
renatofilho@787
   192
  gboolean drained;             /* TRUE if EOS went throug all endpads */
renatofilho@787
   193
  gboolean blocked;             /* TRUE if all endpads are blocked */
renatofilho@787
   194
  gboolean complete;            /* TRUE if we are not expecting anymore streams 
renatofilho@787
   195
                                 * on this group */
renatofilho@787
   196
  gulong overrunsig;
renatofilho@787
   197
  gulong underrunsig;
renatofilho@787
   198
  guint nbdynamic;              /* number of dynamic pads in the group. */
renatofilho@787
   199
renatofilho@787
   200
  GList *endpads;               /* List of GstDecodePad of source pads to be exposed */
renatofilho@787
   201
  GList *ghosts;                /* List of GstGhostPad for the endpads */
renatofilho@787
   202
};
renatofilho@787
   203
renatofilho@787
   204
#define GROUP_MUTEX_LOCK(group) G_STMT_START {				\
renatofilho@787
   205
    GST_LOG_OBJECT (group->dbin,					\
renatofilho@787
   206
		    "locking group %p from thread %p",			\
renatofilho@787
   207
		    group, g_thread_self ());				\
renatofilho@787
   208
    g_mutex_lock (group->lock);						\
renatofilho@787
   209
    GST_LOG_OBJECT (group->dbin,					\
renatofilho@787
   210
		    "locked group %p from thread %p",			\
renatofilho@787
   211
		    group, g_thread_self ());				\
renatofilho@787
   212
} G_STMT_END
renatofilho@787
   213
renatofilho@787
   214
#define GROUP_MUTEX_UNLOCK(group) G_STMT_START {                        \
renatofilho@787
   215
    GST_LOG_OBJECT (group->dbin,					\
renatofilho@787
   216
		    "unlocking group %p from thread %p",		\
renatofilho@787
   217
		    group, g_thread_self ());				\
renatofilho@787
   218
    g_mutex_unlock (group->lock);					\
renatofilho@787
   219
} G_STMT_END
renatofilho@787
   220
renatofilho@787
   221
renatofilho@787
   222
static GstDecodeGroup *gst_decode_group_new (GstDecodeBin * decode_bin);
renatofilho@787
   223
static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
renatofilho@787
   224
    GstPad * pad);
renatofilho@787
   225
static gboolean gst_decode_group_control_source_pad (GstDecodeGroup * group,
renatofilho@787
   226
    GstPad * pad);
renatofilho@787
   227
static gboolean gst_decode_group_expose (GstDecodeGroup * group);
renatofilho@787
   228
static void gst_decode_group_check_if_blocked (GstDecodeGroup * group);
renatofilho@787
   229
static void gst_decode_group_set_complete (GstDecodeGroup * group);
renatofilho@787
   230
static void gst_decode_group_hide (GstDecodeGroup * group);
renatofilho@787
   231
static void gst_decode_group_free (GstDecodeGroup * group);
renatofilho@787
   232
renatofilho@787
   233
/* GstDecodePad
renatofilho@787
   234
 *
renatofilho@787
   235
 * GstPad private used for source pads of groups
renatofilho@787
   236
 */
renatofilho@787
   237
renatofilho@787
   238
struct _GstDecodePad
renatofilho@787
   239
{
renatofilho@787
   240
  GstPad *pad;
renatofilho@787
   241
  GstDecodeGroup *group;
renatofilho@787
   242
  gboolean blocked;
renatofilho@787
   243
  gboolean drained;
renatofilho@787
   244
};
renatofilho@787
   245
renatofilho@787
   246
static GstDecodePad *gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad,
renatofilho@787
   247
    gboolean block);
renatofilho@787
   248
static void source_pad_blocked_cb (GstPad * pad, gboolean blocked,
renatofilho@787
   249
    GstDecodePad * dpad);
renatofilho@787
   250
renatofilho@787
   251
/* TempPadStruct
renatofilho@787
   252
 * Internal structure used for pads which have more than one structure.
renatofilho@787
   253
 */
renatofilho@787
   254
typedef struct _TempPadStruct
renatofilho@787
   255
{
renatofilho@787
   256
  GstDecodeBin *dbin;
renatofilho@787
   257
  GstDecodeGroup *group;
renatofilho@787
   258
} TempPadStruct;
renatofilho@787
   259
renatofilho@787
   260
/********************************
renatofilho@787
   261
 * Standard GObject boilerplate *
renatofilho@787
   262
 ********************************/
renatofilho@787
   263
renatofilho@787
   264
static void gst_decode_bin_class_init (GstDecodeBinClass * klass);
renatofilho@787
   265
static void gst_decode_bin_init (GstDecodeBin * decode_bin);
renatofilho@787
   266
static void gst_decode_bin_dispose (GObject * object);
renatofilho@787
   267
static void gst_decode_bin_finalize (GObject * object);
renatofilho@787
   268
renatofilho@787
   269
static GType
renatofilho@787
   270
gst_decode_bin_get_type (void)
renatofilho@787
   271
{
renatofilho@787
   272
  static GType gst_decode_bin_type = 0;
renatofilho@787
   273
renatofilho@787
   274
  if (!gst_decode_bin_type) {
renatofilho@787
   275
    static const GTypeInfo gst_decode_bin_info = {
renatofilho@787
   276
      sizeof (GstDecodeBinClass),
renatofilho@787
   277
      NULL,
renatofilho@787
   278
      NULL,
renatofilho@787
   279
      (GClassInitFunc) gst_decode_bin_class_init,
renatofilho@787
   280
      NULL,
renatofilho@787
   281
      NULL,
renatofilho@787
   282
      sizeof (GstDecodeBin),
renatofilho@787
   283
      0,
renatofilho@787
   284
      (GInstanceInitFunc) gst_decode_bin_init,
renatofilho@787
   285
      NULL
renatofilho@787
   286
    };
renatofilho@787
   287
renatofilho@787
   288
    gst_decode_bin_type =
renatofilho@787
   289
        g_type_register_static (GST_TYPE_BIN, "GstDecodeBin2",
renatofilho@787
   290
        &gst_decode_bin_info, 0);
renatofilho@787
   291
  }
renatofilho@787
   292
renatofilho@787
   293
  return gst_decode_bin_type;
renatofilho@787
   294
}
renatofilho@787
   295
renatofilho@787
   296
static gboolean
renatofilho@787
   297
_gst_boolean_accumulator (GSignalInvocationHint * ihint,
renatofilho@787
   298
    GValue * return_accu, const GValue * handler_return, gpointer dummy)
renatofilho@787
   299
{
renatofilho@787
   300
  gboolean myboolean;
renatofilho@787
   301
renatofilho@787
   302
  myboolean = g_value_get_boolean (handler_return);
renatofilho@787
   303
  if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
renatofilho@787
   304
    g_value_set_boolean (return_accu, myboolean);
renatofilho@787
   305
renatofilho@787
   306
  /* stop emission if FALSE */
renatofilho@787
   307
  return myboolean;
renatofilho@787
   308
}
renatofilho@787
   309
renatofilho@787
   310
static void
renatofilho@787
   311
gst_decode_bin_class_init (GstDecodeBinClass * klass)
renatofilho@787
   312
{
renatofilho@787
   313
  GObjectClass *gobject_klass;
renatofilho@787
   314
  GstElementClass *gstelement_klass;
renatofilho@787
   315
  GstBinClass *gstbin_klass;
renatofilho@787
   316
renatofilho@787
   317
  gobject_klass = (GObjectClass *) klass;
renatofilho@787
   318
  gstelement_klass = (GstElementClass *) klass;
renatofilho@787
   319
  gstbin_klass = (GstBinClass *) klass;
renatofilho@787
   320
renatofilho@787
   321
  parent_class = g_type_class_peek_parent (klass);
renatofilho@787
   322
renatofilho@787
   323
  gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_decode_bin_dispose);
renatofilho@787
   324
  gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_decode_bin_finalize);
renatofilho@787
   325
  gobject_klass->set_property = GST_DEBUG_FUNCPTR (gst_decode_bin_set_property);
renatofilho@787
   326
  gobject_klass->get_property = GST_DEBUG_FUNCPTR (gst_decode_bin_get_property);
renatofilho@787
   327
renatofilho@787
   328
  /**
renatofilho@787
   329
   * GstDecodeBin2::new-decoded-pad:
renatofilho@787
   330
   * @pad: the newly created pad
renatofilho@787
   331
   * @islast: #TRUE if this is the last pad to be added. Deprecated.
renatofilho@787
   332
   *
renatofilho@787
   333
   * This signal gets emitted as soon as a new pad of the same type as one of
renatofilho@787
   334
   * the valid 'raw' types is added.
renatofilho@787
   335
   */
renatofilho@787
   336
renatofilho@787
   337
  gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD] =
renatofilho@787
   338
      g_signal_new ("new-decoded-pad", G_TYPE_FROM_CLASS (klass),
renatofilho@787
   339
      G_SIGNAL_RUN_LAST,
renatofilho@787
   340
      G_STRUCT_OFFSET (GstDecodeBinClass, new_decoded_pad), NULL, NULL,
renatofilho@787
   341
      gst_play_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2, GST_TYPE_PAD,
renatofilho@787
   342
      G_TYPE_BOOLEAN);
renatofilho@787
   343
renatofilho@787
   344
  /**
renatofilho@787
   345
   * GstDecodeBin2::removed-decoded-pad:
renatofilho@787
   346
   * @pad: the pad that was removed
renatofilho@787
   347
   *
renatofilho@787
   348
   * This signal is emitted when a 'final' caps pad has been removed.
renatofilho@787
   349
   */
renatofilho@787
   350
renatofilho@787
   351
  gst_decode_bin_signals[SIGNAL_REMOVED_DECODED_PAD] =
renatofilho@787
   352
      g_signal_new ("removed-decoded-pad", G_TYPE_FROM_CLASS (klass),
renatofilho@787
   353
      G_SIGNAL_RUN_LAST,
renatofilho@787
   354
      G_STRUCT_OFFSET (GstDecodeBinClass, removed_decoded_pad), NULL, NULL,
renatofilho@787
   355
      gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_PAD);
renatofilho@787
   356
renatofilho@787
   357
  /**
renatofilho@787
   358
   * GstDecodeBin2::unknown-type:
renatofilho@787
   359
   * @pad: the new pad containing caps that cannot be resolved to a 'final' stream type.
renatofilho@787
   360
   * @caps: the #GstCaps of the pad that cannot be resolved.
renatofilho@787
   361
   *
renatofilho@787
   362
   * This signal is emitted when a pad for which there is no further possible
renatofilho@787
   363
   * decoding is added to the decodebin.
renatofilho@787
   364
   */
renatofilho@787
   365
renatofilho@787
   366
  gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
renatofilho@787
   367
      g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
renatofilho@787
   368
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, unknown_type),
renatofilho@787
   369
      NULL, NULL, gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
renatofilho@787
   370
      GST_TYPE_PAD, GST_TYPE_CAPS);
renatofilho@787
   371
renatofilho@787
   372
  /**
renatofilho@787
   373
   * GstDecodeBin2::autoplug-continue:
renatofilho@787
   374
   * @caps: The #GstCaps found.
renatofilho@787
   375
   *
renatofilho@787
   376
   * This signal is emitted whenever decodebin2 finds a new stream. It is
renatofilho@787
   377
   * emitted before looking for any elements that can handle that stream.
renatofilho@787
   378
   *
renatofilho@787
   379
   * Returns: #TRUE if you wish decodebin2 to look for elements that can
renatofilho@787
   380
   * handle the given @caps. If #FALSE, those caps will be considered as
renatofilho@787
   381
   * final and the pad will be exposed as such (see 'new-decoded-pad'
renatofilho@787
   382
   * signal).
renatofilho@787
   383
   */
renatofilho@787
   384
renatofilho@787
   385
  gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
renatofilho@787
   386
      g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
renatofilho@787
   387
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_continue),
renatofilho@787
   388
      _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT,
renatofilho@787
   389
      G_TYPE_BOOLEAN, 1, GST_TYPE_CAPS);
renatofilho@787
   390
renatofilho@787
   391
  /**
renatofilho@787
   392
   * GstDecodeBin2::autoplug-sort:
renatofilho@787
   393
   * @caps: The #GstCaps.
renatofilho@787
   394
   * @factories: A #GList of possible #GstElementFactory to use.
renatofilho@787
   395
   *
renatofilho@787
   396
   * This signal is emitted once decodebin2 has found all the possible
renatofilho@787
   397
   * #GstElementFactory that can be used to handle the given @caps.
renatofilho@787
   398
   *
renatofilho@787
   399
   * UNSTABLE API. Will change soon.
renatofilho@787
   400
   *
renatofilho@787
   401
   * Returns: #TRUE if you wish decodebin2 to start trying to decode
renatofilho@787
   402
   * the given @caps with the list of factories. #FALSE if you do not want
renatofilho@787
   403
   * these #GstCaps, if so the pad will be exposed as unknown (see
renatofilho@787
   404
   * 'unknown-type' signal).
renatofilho@787
   405
   */
renatofilho@787
   406
renatofilho@787
   407
  gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT] =
renatofilho@787
   408
      g_signal_new ("autoplug-sort", G_TYPE_FROM_CLASS (klass),
renatofilho@787
   409
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, autoplug_sort),
renatofilho@787
   410
      _gst_boolean_accumulator, NULL, gst_play_marshal_BOOLEAN__OBJECT_POINTER,
renatofilho@787
   411
      G_TYPE_BOOLEAN, 2, GST_TYPE_CAPS, G_TYPE_POINTER);
renatofilho@787
   412
renatofilho@787
   413
  g_object_class_install_property (gobject_klass, PROP_CAPS,
renatofilho@787
   414
      g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.",
renatofilho@787
   415
          GST_TYPE_CAPS, G_PARAM_READWRITE));
renatofilho@787
   416
renatofilho@787
   417
  klass->autoplug_continue =
renatofilho@787
   418
      GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_continue);
renatofilho@787
   419
  klass->autoplug_sort = GST_DEBUG_FUNCPTR (gst_decode_bin_autoplug_sort);
renatofilho@787
   420
renatofilho@787
   421
  gst_element_class_add_pad_template (gstelement_klass,
renatofilho@787
   422
      gst_static_pad_template_get (&decoder_bin_sink_template));
renatofilho@787
   423
  gst_element_class_add_pad_template (gstelement_klass,
renatofilho@787
   424
      gst_static_pad_template_get (&decoder_bin_src_template));
renatofilho@787
   425
renatofilho@787
   426
  gst_element_class_set_details (gstelement_klass, &gst_decode_bin_details);
renatofilho@787
   427
renatofilho@787
   428
  gstelement_klass->change_state =
renatofilho@787
   429
      GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
renatofilho@787
   430
}
renatofilho@787
   431
renatofilho@787
   432
/* the filter function for selecting the elements we can use in
renatofilho@787
   433
 * autoplugging */
renatofilho@787
   434
static gboolean
renatofilho@787
   435
gst_decode_bin_factory_filter (GstPluginFeature * feature,
renatofilho@787
   436
    GstDecodeBin * decode_bin)
renatofilho@787
   437
{
renatofilho@787
   438
  guint rank;
renatofilho@787
   439
  const gchar *klass;
renatofilho@787
   440
renatofilho@787
   441
  /* we only care about element factories */
renatofilho@787
   442
  if (!GST_IS_ELEMENT_FACTORY (feature))
renatofilho@787
   443
    return FALSE;
renatofilho@787
   444
renatofilho@787
   445
  klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
renatofilho@787
   446
  /* only demuxers, decoders and parsers can play */
renatofilho@787
   447
  if (strstr (klass, "Demux") == NULL &&
renatofilho@787
   448
      strstr (klass, "Decoder") == NULL && strstr (klass, "Parse") == NULL) {
renatofilho@787
   449
    return FALSE;
renatofilho@787
   450
  }
renatofilho@787
   451
renatofilho@787
   452
  /* only select elements with autoplugging rank */
renatofilho@787
   453
  rank = gst_plugin_feature_get_rank (feature);
renatofilho@787
   454
  if (rank < GST_RANK_MARGINAL)
renatofilho@787
   455
    return FALSE;
renatofilho@787
   456
renatofilho@787
   457
  return TRUE;
renatofilho@787
   458
}
renatofilho@787
   459
renatofilho@787
   460
/* function used to sort element features */
renatofilho@787
   461
static gint
renatofilho@787
   462
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
renatofilho@787
   463
{
renatofilho@787
   464
  gint diff;
renatofilho@787
   465
  const gchar *rname1, *rname2;
renatofilho@787
   466
renatofilho@787
   467
  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
renatofilho@787
   468
  if (diff != 0)
renatofilho@787
   469
    return diff;
renatofilho@787
   470
renatofilho@787
   471
  rname1 = gst_plugin_feature_get_name (f1);
renatofilho@787
   472
  rname2 = gst_plugin_feature_get_name (f2);
renatofilho@787
   473
renatofilho@787
   474
  diff = strcmp (rname2, rname1);
renatofilho@787
   475
renatofilho@787
   476
  return diff;
renatofilho@787
   477
}
renatofilho@787
   478
renatofilho@787
   479
static void
renatofilho@787
   480
print_feature (GstPluginFeature * feature)
renatofilho@787
   481
{
renatofilho@787
   482
  const gchar *rname;
renatofilho@787
   483
renatofilho@787
   484
  rname = gst_plugin_feature_get_name (feature);
renatofilho@787
   485
renatofilho@787
   486
  GST_DEBUG ("%s", rname);
renatofilho@787
   487
}
renatofilho@787
   488
renatofilho@787
   489
static void
renatofilho@787
   490
gst_decode_bin_init (GstDecodeBin * decode_bin)
renatofilho@787
   491
{
renatofilho@787
   492
  GList *factories;
renatofilho@787
   493
renatofilho@787
   494
  /* first filter out the interesting element factories */
renatofilho@787
   495
  factories = gst_default_registry_feature_filter (
renatofilho@787
   496
      (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
renatofilho@787
   497
      FALSE, decode_bin);
renatofilho@787
   498
renatofilho@787
   499
  /* sort them according to their ranks */
renatofilho@787
   500
  decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
renatofilho@787
   501
  /* do some debugging */
renatofilho@787
   502
  g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
renatofilho@787
   503
renatofilho@787
   504
renatofilho@787
   505
  /* we create the typefind element only once */
renatofilho@787
   506
  decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
renatofilho@787
   507
  if (!decode_bin->typefind) {
renatofilho@787
   508
    g_warning ("can't find typefind element, decodebin will not work");
renatofilho@787
   509
  } else {
renatofilho@787
   510
    GstPad *pad;
renatofilho@787
   511
    GstPad *gpad;
renatofilho@787
   512
renatofilho@787
   513
    /* add the typefind element */
renatofilho@787
   514
    if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind)) {
renatofilho@787
   515
      g_warning ("Could not add typefind element, decodebin will not work");
renatofilho@787
   516
      gst_object_unref (decode_bin->typefind);
renatofilho@787
   517
      decode_bin->typefind = NULL;
renatofilho@787
   518
    }
renatofilho@787
   519
renatofilho@787
   520
    /* get the sinkpad */
renatofilho@787
   521
    pad = gst_element_get_pad (decode_bin->typefind, "sink");
renatofilho@787
   522
renatofilho@787
   523
    /* ghost the sink pad to ourself */
renatofilho@787
   524
    gpad = gst_ghost_pad_new ("sink", pad);
renatofilho@787
   525
    gst_pad_set_active (gpad, TRUE);
renatofilho@787
   526
    gst_element_add_pad (GST_ELEMENT (decode_bin), gpad);
renatofilho@787
   527
renatofilho@787
   528
    gst_object_unref (pad);
renatofilho@787
   529
renatofilho@787
   530
    /* connect a signal to find out when the typefind element found
renatofilho@787
   531
     * a type */
renatofilho@787
   532
    g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
renatofilho@787
   533
        G_CALLBACK (type_found), decode_bin);
renatofilho@787
   534
  }
renatofilho@787
   535
renatofilho@787
   536
  decode_bin->lock = g_mutex_new ();
renatofilho@787
   537
  decode_bin->activegroup = NULL;
renatofilho@787
   538
  decode_bin->groups = NULL;
renatofilho@787
   539
renatofilho@787
   540
  decode_bin->caps =
renatofilho@787
   541
      gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray;"
renatofilho@787
   542
      "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup");
renatofilho@787
   543
renatofilho@787
   544
  add_fakesink (decode_bin);
renatofilho@787
   545
renatofilho@787
   546
  /* FILLME */
renatofilho@787
   547
}
renatofilho@787
   548
renatofilho@787
   549
static void
renatofilho@787
   550
gst_decode_bin_dispose (GObject * object)
renatofilho@787
   551
{
renatofilho@787
   552
  GstDecodeBin *decode_bin;
renatofilho@787
   553
  GList *tmp;
renatofilho@787
   554
renatofilho@787
   555
  decode_bin = GST_DECODE_BIN (object);
renatofilho@787
   556
renatofilho@787
   557
  if (decode_bin->factories)
renatofilho@787
   558
    gst_plugin_feature_list_free (decode_bin->factories);
renatofilho@787
   559
  decode_bin->factories = NULL;
renatofilho@787
   560
renatofilho@787
   561
  if (decode_bin->activegroup) {
renatofilho@787
   562
    gst_decode_group_free (decode_bin->activegroup);
renatofilho@787
   563
    decode_bin->activegroup = NULL;
renatofilho@787
   564
  }
renatofilho@787
   565
renatofilho@787
   566
  /* remove groups */
renatofilho@787
   567
  for (tmp = decode_bin->groups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   568
    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
renatofilho@787
   569
renatofilho@787
   570
    gst_decode_group_free (group);
renatofilho@787
   571
  }
renatofilho@787
   572
  g_list_free (decode_bin->groups);
renatofilho@787
   573
  decode_bin->groups = NULL;
renatofilho@787
   574
renatofilho@787
   575
  for (tmp = decode_bin->oldgroups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   576
    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
renatofilho@787
   577
renatofilho@787
   578
    gst_decode_group_free (group);
renatofilho@787
   579
  }
renatofilho@787
   580
  g_list_free (decode_bin->oldgroups);
renatofilho@787
   581
  decode_bin->oldgroups = NULL;
renatofilho@787
   582
renatofilho@787
   583
  if (decode_bin->caps)
renatofilho@787
   584
    gst_caps_unref (decode_bin->caps);
renatofilho@787
   585
  decode_bin->caps = NULL;
renatofilho@787
   586
  remove_fakesink (decode_bin);
renatofilho@787
   587
renatofilho@787
   588
  G_OBJECT_CLASS (parent_class)->dispose (object);
renatofilho@787
   589
}
renatofilho@787
   590
renatofilho@787
   591
static void
renatofilho@787
   592
gst_decode_bin_finalize (GObject * object)
renatofilho@787
   593
{
renatofilho@787
   594
  GstDecodeBin *decode_bin;
renatofilho@787
   595
renatofilho@787
   596
  decode_bin = GST_DECODE_BIN (object);
renatofilho@787
   597
renatofilho@787
   598
  if (decode_bin->lock) {
renatofilho@787
   599
    g_mutex_free (decode_bin->lock);
renatofilho@787
   600
    decode_bin->lock = NULL;
renatofilho@787
   601
  }
renatofilho@787
   602
renatofilho@787
   603
  G_OBJECT_CLASS (parent_class)->finalize (object);
renatofilho@787
   604
}
renatofilho@787
   605
renatofilho@787
   606
static void
renatofilho@787
   607
gst_decode_bin_set_property (GObject * object, guint prop_id,
renatofilho@787
   608
    const GValue * value, GParamSpec * pspec)
renatofilho@787
   609
{
renatofilho@787
   610
  GstDecodeBin *dbin;
renatofilho@787
   611
renatofilho@787
   612
  dbin = GST_DECODE_BIN (object);
renatofilho@787
   613
renatofilho@787
   614
  switch (prop_id) {
renatofilho@787
   615
    case PROP_CAPS:
renatofilho@787
   616
      gst_decode_bin_set_caps (dbin, (GstCaps *) g_value_dup_boxed (value));
renatofilho@787
   617
      break;
renatofilho@787
   618
    default:
renatofilho@787
   619
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
renatofilho@787
   620
      break;
renatofilho@787
   621
  }
renatofilho@787
   622
}
renatofilho@787
   623
renatofilho@787
   624
static void
renatofilho@787
   625
gst_decode_bin_get_property (GObject * object, guint prop_id,
renatofilho@787
   626
    GValue * value, GParamSpec * pspec)
renatofilho@787
   627
{
renatofilho@787
   628
  GstDecodeBin *dbin;
renatofilho@787
   629
renatofilho@787
   630
  dbin = GST_DECODE_BIN (object);
renatofilho@787
   631
  switch (prop_id) {
renatofilho@787
   632
    case PROP_CAPS:{
renatofilho@787
   633
      g_value_take_boxed (value, gst_decode_bin_get_caps (dbin));
renatofilho@787
   634
      break;
renatofilho@787
   635
    }
renatofilho@787
   636
    default:
renatofilho@787
   637
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
renatofilho@787
   638
      break;
renatofilho@787
   639
  }
renatofilho@787
   640
renatofilho@787
   641
}
renatofilho@787
   642
renatofilho@787
   643
/* _set_caps
renatofilho@787
   644
 * Changes the caps on which decodebin will stop decoding.
renatofilho@787
   645
 * Will unref the previously set one. The refcount of the given caps will be
renatofilho@787
   646
 * taken.
renatofilho@787
   647
 * @caps can be NULL.
renatofilho@787
   648
 *
renatofilho@787
   649
 * MT-safe
renatofilho@787
   650
 */
renatofilho@787
   651
renatofilho@787
   652
static void
renatofilho@787
   653
gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps)
renatofilho@787
   654
{
renatofilho@787
   655
  GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
renatofilho@787
   656
renatofilho@787
   657
  DECODE_BIN_LOCK (dbin);
renatofilho@787
   658
  if (dbin->caps)
renatofilho@787
   659
    gst_caps_unref (dbin->caps);
renatofilho@787
   660
  dbin->caps = caps;
renatofilho@787
   661
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   662
}
renatofilho@787
   663
renatofilho@787
   664
/* _get_caps
renatofilho@787
   665
 * Returns the currently configured caps on which decodebin will stop decoding.
renatofilho@787
   666
 * The returned caps (if not NULL), will have its refcount incremented.
renatofilho@787
   667
 *
renatofilho@787
   668
 * MT-safe
renatofilho@787
   669
 */
renatofilho@787
   670
renatofilho@787
   671
static GstCaps *
renatofilho@787
   672
gst_decode_bin_get_caps (GstDecodeBin * dbin)
renatofilho@787
   673
{
renatofilho@787
   674
  GstCaps *caps;
renatofilho@787
   675
renatofilho@787
   676
  GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
renatofilho@787
   677
renatofilho@787
   678
  DECODE_BIN_LOCK (dbin);
renatofilho@787
   679
  caps = dbin->caps;
renatofilho@787
   680
  if (caps)
renatofilho@787
   681
    gst_caps_ref (caps);
renatofilho@787
   682
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   683
renatofilho@787
   684
  return caps;
renatofilho@787
   685
}
renatofilho@787
   686
renatofilho@787
   687
/*****
renatofilho@787
   688
 * Default autoplug signal handlers
renatofilho@787
   689
 *****/
renatofilho@787
   690
renatofilho@787
   691
static gboolean
renatofilho@787
   692
gst_decode_bin_autoplug_continue (GstElement * element, GstCaps * caps)
renatofilho@787
   693
{
renatofilho@787
   694
  return TRUE;
renatofilho@787
   695
}
renatofilho@787
   696
renatofilho@787
   697
static gboolean
renatofilho@787
   698
gst_decode_bin_autoplug_sort (GstElement * element, GstCaps * caps,
renatofilho@787
   699
    GList ** list)
renatofilho@787
   700
{
renatofilho@787
   701
  return TRUE;
renatofilho@787
   702
}
renatofilho@787
   703
renatofilho@787
   704
renatofilho@787
   705
renatofilho@787
   706
/********
renatofilho@787
   707
 * Discovery methods
renatofilho@787
   708
 *****/
renatofilho@787
   709
renatofilho@787
   710
static gboolean are_raw_caps (GstDecodeBin * dbin, GstCaps * caps);
renatofilho@787
   711
static gboolean is_demuxer_element (GstElement * srcelement);
renatofilho@787
   712
static GList *find_compatibles (GstDecodeBin * decode_bin,
renatofilho@787
   713
    const GstCaps * caps);
renatofilho@787
   714
renatofilho@787
   715
static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
renatofilho@787
   716
    GstPad * pad, GList * factories, GstDecodeGroup * group);
renatofilho@787
   717
static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
renatofilho@787
   718
    GstDecodeGroup * group);
renatofilho@787
   719
static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   720
    GstDecodeGroup * group);
renatofilho@787
   721
renatofilho@787
   722
static void pad_added_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
   723
    GstDecodeGroup * group);
renatofilho@787
   724
static void pad_removed_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
   725
    GstDecodeGroup * group);
renatofilho@787
   726
static void no_more_pads_group_cb (GstElement * element,
renatofilho@787
   727
    GstDecodeGroup * group);
renatofilho@787
   728
static void pad_added_cb (GstElement * element, GstPad * pad,
renatofilho@787
   729
    GstDecodeBin * dbin);
renatofilho@787
   730
static void pad_removed_cb (GstElement * element, GstPad * pad,
renatofilho@787
   731
    GstDecodeBin * dbin);
renatofilho@787
   732
static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin);
renatofilho@787
   733
renatofilho@787
   734
static GstDecodeGroup *get_current_group (GstDecodeBin * dbin);
renatofilho@787
   735
renatofilho@787
   736
static void
renatofilho@787
   737
analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   738
    GstCaps * caps, GstDecodeGroup * group)
renatofilho@787
   739
{
renatofilho@787
   740
  gboolean apcontinue = TRUE;
renatofilho@787
   741
  GList *factories = NULL;
renatofilho@787
   742
  gboolean apsort = TRUE;
renatofilho@787
   743
renatofilho@787
   744
  GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
renatofilho@787
   745
      GST_DEBUG_PAD_NAME (pad), caps);
renatofilho@787
   746
renatofilho@787
   747
  if ((caps == NULL) || gst_caps_is_empty (caps))
renatofilho@787
   748
    goto unknown_type;
renatofilho@787
   749
renatofilho@787
   750
  if (gst_caps_is_any (caps))
renatofilho@787
   751
    goto any_caps;
renatofilho@787
   752
renatofilho@787
   753
  /* 1. Emit 'autoplug-continue' */
renatofilho@787
   754
  g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   755
      gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, caps, &apcontinue);
renatofilho@787
   756
renatofilho@787
   757
  /* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */
renatofilho@787
   758
  if ((!apcontinue) || are_raw_caps (dbin, caps))
renatofilho@787
   759
    goto expose_pad;
renatofilho@787
   760
renatofilho@787
   761
  /* 1.b else if there's no compatible factory or 'autoplug-sort' returned FALSE, goto pad_not_used */
renatofilho@787
   762
  if ((factories = find_compatibles (dbin, caps))) {
renatofilho@787
   763
    /* emit autoplug-sort */
renatofilho@787
   764
    g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   765
        gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT],
renatofilho@787
   766
        0, caps, &factories, &apsort);
renatofilho@787
   767
    if (!apsort) {
renatofilho@787
   768
      g_list_free (factories);
renatofilho@787
   769
      /* User doesn't want that pad */
renatofilho@787
   770
      goto pad_not_wanted;
renatofilho@787
   771
    }
renatofilho@787
   772
  } else {
renatofilho@787
   773
    /* no compatible factories */
renatofilho@787
   774
    goto unknown_type;
renatofilho@787
   775
  }
renatofilho@787
   776
renatofilho@787
   777
  /* 1.c else goto pad_is_valid */
renatofilho@787
   778
  GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
renatofilho@787
   779
renatofilho@787
   780
  connect_pad (dbin, src, pad, factories, group);
renatofilho@787
   781
  g_list_free (factories);
renatofilho@787
   782
renatofilho@787
   783
  return;
renatofilho@787
   784
renatofilho@787
   785
expose_pad:
renatofilho@787
   786
  {
renatofilho@787
   787
    GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue);
renatofilho@787
   788
    expose_pad (dbin, src, pad, group);
renatofilho@787
   789
    return;
renatofilho@787
   790
  }
renatofilho@787
   791
renatofilho@787
   792
pad_not_wanted:
renatofilho@787
   793
  {
renatofilho@787
   794
    GST_LOG_OBJECT (pad, "User doesn't want this pad, stopping discovery");
renatofilho@787
   795
    return;
renatofilho@787
   796
  }
renatofilho@787
   797
renatofilho@787
   798
unknown_type:
renatofilho@787
   799
  {
renatofilho@787
   800
    GST_LOG_OBJECT (pad, "Unknown type, firing signal");
renatofilho@787
   801
    g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   802
        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
renatofilho@787
   803
renatofilho@787
   804
    /* Check if there are no pending groups, if so, remove fakesink */
renatofilho@787
   805
    if (dbin->groups == NULL)
renatofilho@787
   806
      remove_fakesink (dbin);
renatofilho@787
   807
renatofilho@787
   808
    return;
renatofilho@787
   809
  }
renatofilho@787
   810
renatofilho@787
   811
any_caps:
renatofilho@787
   812
  {
renatofilho@787
   813
    GST_WARNING_OBJECT (pad,
renatofilho@787
   814
        "pad has ANY caps, not able to autoplug to anything");
renatofilho@787
   815
    /* FIXME : connect to caps notification */
renatofilho@787
   816
    return;
renatofilho@787
   817
  }
renatofilho@787
   818
}
renatofilho@787
   819
renatofilho@787
   820
renatofilho@787
   821
/* connect_pad:
renatofilho@787
   822
 *
renatofilho@787
   823
 * Try to connect the given pad to an element created from one of the factories,
renatofilho@787
   824
 * and recursively.
renatofilho@787
   825
 *
renatofilho@787
   826
 * Returns TRUE if an element was properly created and linked
renatofilho@787
   827
 */
renatofilho@787
   828
renatofilho@787
   829
static gboolean
renatofilho@787
   830
connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   831
    GList * factories, GstDecodeGroup * group)
renatofilho@787
   832
{
renatofilho@787
   833
  gboolean res = FALSE;
renatofilho@787
   834
  GList *tmp;
renatofilho@787
   835
renatofilho@787
   836
  g_return_val_if_fail (factories != NULL, FALSE);
renatofilho@787
   837
  GST_DEBUG_OBJECT (dbin, "pad %s:%s , group:%p",
renatofilho@787
   838
      GST_DEBUG_PAD_NAME (pad), group);
renatofilho@787
   839
renatofilho@787
   840
  /* 1. is element demuxer or parser */
renatofilho@787
   841
  if (is_demuxer_element (src)) {
renatofilho@787
   842
    GstPad *mqpad;
renatofilho@787
   843
renatofilho@787
   844
    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
renatofilho@787
   845
renatofilho@787
   846
    if (!group)
renatofilho@787
   847
      if (!(group = get_current_group (dbin))) {
renatofilho@787
   848
        group = gst_decode_group_new (dbin);
renatofilho@787
   849
        DECODE_BIN_LOCK (dbin);
renatofilho@787
   850
        dbin->groups = g_list_append (dbin->groups, group);
renatofilho@787
   851
        DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   852
      }
renatofilho@787
   853
renatofilho@787
   854
    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
renatofilho@787
   855
      goto beach;
renatofilho@787
   856
    pad = mqpad;
renatofilho@787
   857
  }
renatofilho@787
   858
renatofilho@787
   859
  /* 2. Try to create an element and link to it */
renatofilho@787
   860
  for (tmp = factories; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   861
    GstElementFactory *factory = (GstElementFactory *) tmp->data;
renatofilho@787
   862
    GstElement *element;
renatofilho@787
   863
    GstPad *sinkpad;
renatofilho@787
   864
renatofilho@787
   865
    /* 2.1. Try to create an element */
renatofilho@787
   866
    if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
renatofilho@787
   867
      GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
renatofilho@787
   868
          gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
renatofilho@787
   869
      continue;
renatofilho@787
   870
    }
renatofilho@787
   871
renatofilho@787
   872
    /* 2.3. Find its sink pad */
renatofilho@787
   873
    if (!(sinkpad = find_sink_pad (element))) {
renatofilho@787
   874
      GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
renatofilho@787
   875
          GST_ELEMENT_NAME (element));
renatofilho@787
   876
      gst_object_unref (element);
renatofilho@787
   877
      continue;
renatofilho@787
   878
    }
renatofilho@787
   879
renatofilho@787
   880
    /* 2.4 add it ... */
renatofilho@787
   881
    if (!(gst_bin_add (GST_BIN (dbin), element))) {
renatofilho@787
   882
      GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
renatofilho@787
   883
          GST_ELEMENT_NAME (element));
renatofilho@787
   884
      gst_object_unref (sinkpad);
renatofilho@787
   885
      gst_object_unref (element);
renatofilho@787
   886
      continue;
renatofilho@787
   887
    }
renatofilho@787
   888
renatofilho@787
   889
    /* ... activate it ... */
renatofilho@787
   890
    if ((gst_element_set_state (element,
renatofilho@787
   891
                GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
renatofilho@787
   892
      GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
renatofilho@787
   893
          GST_ELEMENT_NAME (element));
renatofilho@787
   894
      gst_object_unref (sinkpad);
renatofilho@787
   895
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   896
      continue;
renatofilho@787
   897
    }
renatofilho@787
   898
renatofilho@787
   899
    /* 2.5 ...and try to link */
renatofilho@787
   900
    if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
renatofilho@787
   901
      GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
renatofilho@787
   902
          GST_DEBUG_PAD_NAME (sinkpad));
renatofilho@787
   903
      gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
   904
      gst_object_unref (sinkpad);
renatofilho@787
   905
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   906
      continue;
renatofilho@787
   907
    }
renatofilho@787
   908
renatofilho@787
   909
    GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
renatofilho@787
   910
renatofilho@787
   911
    /* link this element further */
renatofilho@787
   912
    connect_element (dbin, element, group);
renatofilho@787
   913
renatofilho@787
   914
    /* Bring the element to the state of the parent */
renatofilho@787
   915
    if ((gst_element_set_state (element,
renatofilho@787
   916
                GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
renatofilho@787
   917
      GST_WARNING_OBJECT (dbin, "Couldn't set %s to PAUSED",
renatofilho@787
   918
          GST_ELEMENT_NAME (element));
renatofilho@787
   919
      gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
   920
      gst_object_unref (sinkpad);
renatofilho@787
   921
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   922
      continue;
renatofilho@787
   923
    }
renatofilho@787
   924
renatofilho@787
   925
    res = TRUE;
renatofilho@787
   926
    break;
renatofilho@787
   927
  }
renatofilho@787
   928
renatofilho@787
   929
beach:
renatofilho@787
   930
  return res;
renatofilho@787
   931
}
renatofilho@787
   932
renatofilho@787
   933
static gboolean
renatofilho@787
   934
connect_element (GstDecodeBin * dbin, GstElement * element,
renatofilho@787
   935
    GstDecodeGroup * group)
renatofilho@787
   936
{
renatofilho@787
   937
  GList *pads;
renatofilho@787
   938
  gboolean res = TRUE;
renatofilho@787
   939
  gboolean dynamic = FALSE;
renatofilho@787
   940
  GList *to_connect = NULL;
renatofilho@787
   941
renatofilho@787
   942
  GST_DEBUG_OBJECT (dbin, "Attempting to connect element %s [group:%p] further",
renatofilho@787
   943
      GST_ELEMENT_NAME (element), group);
renatofilho@787
   944
renatofilho@787
   945
  /* 1. Loop over pad templates, grabbing existing pads along the way */
renatofilho@787
   946
  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
renatofilho@787
   947
      pads = g_list_next (pads)) {
renatofilho@787
   948
    GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
renatofilho@787
   949
    const gchar *templ_name;
renatofilho@787
   950
renatofilho@787
   951
    /* we are only interested in source pads */
renatofilho@787
   952
    if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
renatofilho@787
   953
      continue;
renatofilho@787
   954
renatofilho@787
   955
    templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
renatofilho@787
   956
    GST_DEBUG_OBJECT (dbin, "got a source pad template %s", templ_name);
renatofilho@787
   957
renatofilho@787
   958
    /* figure out what kind of pad this is */
renatofilho@787
   959
    switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
renatofilho@787
   960
      case GST_PAD_ALWAYS:
renatofilho@787
   961
      {
renatofilho@787
   962
        /* get the pad that we need to autoplug */
renatofilho@787
   963
        GstPad *pad = gst_element_get_pad (element, templ_name);
renatofilho@787
   964
renatofilho@787
   965
        if (pad) {
renatofilho@787
   966
          GST_DEBUG_OBJECT (dbin, "got the pad for always template %s",
renatofilho@787
   967
              templ_name);
renatofilho@787
   968
          /* here is the pad, we need to autoplug it */
renatofilho@787
   969
          to_connect = g_list_prepend (to_connect, pad);
renatofilho@787
   970
        } else {
renatofilho@787
   971
          /* strange, pad is marked as always but it's not
renatofilho@787
   972
           * there. Fix the element */
renatofilho@787
   973
          GST_WARNING_OBJECT (dbin,
renatofilho@787
   974
              "could not get the pad for always template %s", templ_name);
renatofilho@787
   975
        }
renatofilho@787
   976
        break;
renatofilho@787
   977
      }
renatofilho@787
   978
      case GST_PAD_SOMETIMES:
renatofilho@787
   979
      {
renatofilho@787
   980
        /* try to get the pad to see if it is already created or
renatofilho@787
   981
         * not */
renatofilho@787
   982
        GstPad *pad = gst_element_get_pad (element, templ_name);
renatofilho@787
   983
renatofilho@787
   984
        if (pad) {
renatofilho@787
   985
          GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s",
renatofilho@787
   986
              templ_name);
renatofilho@787
   987
          /* the pad is created, we need to autoplug it */
renatofilho@787
   988
          to_connect = g_list_prepend (to_connect, pad);
renatofilho@787
   989
        } else {
renatofilho@787
   990
          GST_DEBUG_OBJECT (dbin,
renatofilho@787
   991
              "did not get the sometimes pad of template %s", templ_name);
renatofilho@787
   992
          /* we have an element that will create dynamic pads */
renatofilho@787
   993
          dynamic = TRUE;
renatofilho@787
   994
        }
renatofilho@787
   995
        break;
renatofilho@787
   996
      }
renatofilho@787
   997
      case GST_PAD_REQUEST:
renatofilho@787
   998
        /* ignore request pads */
renatofilho@787
   999
        GST_DEBUG_OBJECT (dbin, "ignoring request padtemplate %s", templ_name);
renatofilho@787
  1000
        break;
renatofilho@787
  1001
    }
renatofilho@787
  1002
  }
renatofilho@787
  1003
renatofilho@787
  1004
  /* 2. if there are more potential pads, connect to relevent signals */
renatofilho@787
  1005
  if (dynamic) {
renatofilho@787
  1006
    if (group) {
renatofilho@787
  1007
      GST_LOG ("Adding signals to element %s in group %p",
renatofilho@787
  1008
          GST_ELEMENT_NAME (element), group);
renatofilho@787
  1009
      GROUP_MUTEX_LOCK (group);
renatofilho@787
  1010
      group->nbdynamic++;
renatofilho@787
  1011
      GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
renatofilho@787
  1012
      GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1013
      g_signal_connect (G_OBJECT (element), "pad-added",
renatofilho@787
  1014
          G_CALLBACK (pad_added_group_cb), group);
renatofilho@787
  1015
      g_signal_connect (G_OBJECT (element), "pad-removed",
renatofilho@787
  1016
          G_CALLBACK (pad_removed_group_cb), group);
renatofilho@787
  1017
      g_signal_connect (G_OBJECT (element), "no-more-pads",
renatofilho@787
  1018
          G_CALLBACK (no_more_pads_group_cb), group);
renatofilho@787
  1019
    } else {
renatofilho@787
  1020
      /* This is a non-grouped element, the handlers are different */
renatofilho@787
  1021
      g_signal_connect (G_OBJECT (element), "pad-added",
renatofilho@787
  1022
          G_CALLBACK (pad_added_cb), dbin);
renatofilho@787
  1023
      g_signal_connect (G_OBJECT (element), "pad-removed",
renatofilho@787
  1024
          G_CALLBACK (pad_removed_cb), dbin);
renatofilho@787
  1025
      g_signal_connect (G_OBJECT (element), "no-more-pads",
renatofilho@787
  1026
          G_CALLBACK (no_more_pads_cb), dbin);
renatofilho@787
  1027
    }
renatofilho@787
  1028
  }
renatofilho@787
  1029
renatofilho@787
  1030
  /* 3. for every available pad, connect it */
renatofilho@787
  1031
  for (pads = to_connect; pads; pads = g_list_next (pads)) {
renatofilho@787
  1032
    GstPad *pad = GST_PAD_CAST (pads->data);
renatofilho@787
  1033
    GstCaps *caps;
renatofilho@787
  1034
renatofilho@787
  1035
    caps = gst_pad_get_caps (pad);
renatofilho@787
  1036
    analyze_new_pad (dbin, element, pad, caps, group);
renatofilho@787
  1037
    if (caps)
renatofilho@787
  1038
      gst_caps_unref (caps);
renatofilho@787
  1039
renatofilho@787
  1040
    gst_object_unref (pad);
renatofilho@787
  1041
  }
renatofilho@787
  1042
  g_list_free (to_connect);
renatofilho@787
  1043
renatofilho@787
  1044
  return res;
renatofilho@787
  1045
}
renatofilho@787
  1046
renatofilho@787
  1047
/* expose_pad:
renatofilho@787
  1048
 *
renatofilho@787
  1049
 * Expose the given pad on the group as a decoded pad.
renatofilho@787
  1050
 * If group is NULL, a GstDecodeGroup will be created and setup properly.
renatofilho@787
  1051
 */
renatofilho@787
  1052
static void
renatofilho@787
  1053
expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
  1054
    GstDecodeGroup * group)
renatofilho@787
  1055
{
renatofilho@787
  1056
  gboolean newgroup = FALSE;
renatofilho@787
  1057
  gboolean isdemux;
renatofilho@787
  1058
renatofilho@787
  1059
  GST_DEBUG_OBJECT (dbin, "pad %s:%s, group:%p",
renatofilho@787
  1060
      GST_DEBUG_PAD_NAME (pad), group);
renatofilho@787
  1061
renatofilho@787
  1062
  if (!group)
renatofilho@787
  1063
    if (!(group = get_current_group (dbin))) {
renatofilho@787
  1064
      group = gst_decode_group_new (dbin);
renatofilho@787
  1065
      DECODE_BIN_LOCK (dbin);
renatofilho@787
  1066
      dbin->groups = g_list_append (dbin->groups, group);
renatofilho@787
  1067
      DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1068
      newgroup = TRUE;
renatofilho@787
  1069
    }
renatofilho@787
  1070
renatofilho@787
  1071
  isdemux = is_demuxer_element (src);
renatofilho@787
  1072
renatofilho@787
  1073
  if (isdemux || newgroup) {
renatofilho@787
  1074
    GstPad *mqpad;
renatofilho@787
  1075
renatofilho@787
  1076
    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
renatofilho@787
  1077
renatofilho@787
  1078
    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
renatofilho@787
  1079
      goto beach;
renatofilho@787
  1080
    pad = mqpad;
renatofilho@787
  1081
  }
renatofilho@787
  1082
renatofilho@787
  1083
  gst_decode_group_control_source_pad (group, pad);
renatofilho@787
  1084
renatofilho@787
  1085
  if (newgroup && !isdemux) {
renatofilho@787
  1086
    /* If we have discovered a raw pad and it doesn't belong to any group,
renatofilho@787
  1087
     * that means there wasn't any demuxer. In that case, we consider the
renatofilho@787
  1088
     * group as being complete. */
renatofilho@787
  1089
    gst_decode_group_set_complete (group);
renatofilho@787
  1090
  }
renatofilho@787
  1091
beach:
renatofilho@787
  1092
  return;
renatofilho@787
  1093
}
renatofilho@787
  1094
renatofilho@787
  1095
static void
renatofilho@787
  1096
type_found (GstElement * typefind, guint probability,
renatofilho@787
  1097
    GstCaps * caps, GstDecodeBin * decode_bin)
renatofilho@787
  1098
{
renatofilho@787
  1099
  GstPad *pad;
renatofilho@787
  1100
renatofilho@787
  1101
  GST_STATE_LOCK (decode_bin);
renatofilho@787
  1102
renatofilho@787
  1103
  GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
renatofilho@787
  1104
renatofilho@787
  1105
  pad = gst_element_get_pad (typefind, "src");
renatofilho@787
  1106
renatofilho@787
  1107
  analyze_new_pad (decode_bin, typefind, pad, caps, NULL);
renatofilho@787
  1108
renatofilho@787
  1109
  gst_object_unref (pad);
renatofilho@787
  1110
renatofilho@787
  1111
  GST_STATE_UNLOCK (decode_bin);
renatofilho@787
  1112
  return;
renatofilho@787
  1113
}
renatofilho@787
  1114
renatofilho@787
  1115
static void
renatofilho@787
  1116
pad_added_group_cb (GstElement * element, GstPad * pad, GstDecodeGroup * group)
renatofilho@787
  1117
{
renatofilho@787
  1118
  GstCaps *caps;
renatofilho@787
  1119
  gboolean expose = FALSE;
renatofilho@787
  1120
renatofilho@787
  1121
  GST_LOG_OBJECT (pad, "pad added, group:%p", group);
renatofilho@787
  1122
renatofilho@787
  1123
  caps = gst_pad_get_caps (pad);
renatofilho@787
  1124
  analyze_new_pad (group->dbin, element, pad, caps, group);
renatofilho@787
  1125
  if (caps)
renatofilho@787
  1126
    gst_caps_unref (caps);
renatofilho@787
  1127
renatofilho@787
  1128
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1129
  group->nbdynamic--;
renatofilho@787
  1130
  GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic);
renatofilho@787
  1131
  if (group->nbdynamic == 0)
renatofilho@787
  1132
    expose = TRUE;
renatofilho@787
  1133
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1134
  if (expose) {
renatofilho@787
  1135
    GST_LOG
renatofilho@787
  1136
        ("That was the last dynamic object, now attempting to expose the group");
renatofilho@787
  1137
    DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1138
    gst_decode_group_expose (group);
renatofilho@787
  1139
    DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1140
  }
renatofilho@787
  1141
}
renatofilho@787
  1142
renatofilho@787
  1143
static void
renatofilho@787
  1144
pad_removed_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
  1145
    GstDecodeGroup * group)
renatofilho@787
  1146
{
renatofilho@787
  1147
  GST_LOG_OBJECT (pad, "pad removed, group:%p", group);
renatofilho@787
  1148
renatofilho@787
  1149
  /* In fact, we don't have to do anything here, the active group will be
renatofilho@787
  1150
   * removed when the group's multiqueue is drained */
renatofilho@787
  1151
}
renatofilho@787
  1152
renatofilho@787
  1153
static void
renatofilho@787
  1154
no_more_pads_group_cb (GstElement * element, GstDecodeGroup * group)
renatofilho@787
  1155
{
renatofilho@787
  1156
  GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group);
renatofilho@787
  1157
renatofilho@787
  1158
  /* FIXME : FILLME */
renatofilho@787
  1159
  gst_decode_group_set_complete (group);
renatofilho@787
  1160
}
renatofilho@787
  1161
renatofilho@787
  1162
static void
renatofilho@787
  1163
pad_added_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
renatofilho@787
  1164
{
renatofilho@787
  1165
  GstCaps *caps;
renatofilho@787
  1166
renatofilho@787
  1167
  GST_LOG_OBJECT (pad, "Pad added to non-grouped element");
renatofilho@787
  1168
renatofilho@787
  1169
  caps = gst_pad_get_caps (pad);
renatofilho@787
  1170
  analyze_new_pad (dbin, element, pad, caps, NULL);
renatofilho@787
  1171
  if (caps)
renatofilho@787
  1172
    gst_caps_unref (caps);
renatofilho@787
  1173
}
renatofilho@787
  1174
renatofilho@787
  1175
static void
renatofilho@787
  1176
pad_removed_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
renatofilho@787
  1177
{
renatofilho@787
  1178
  GST_LOG_OBJECT (pad, "Pad removed from non-grouped element");
renatofilho@787
  1179
}
renatofilho@787
  1180
renatofilho@787
  1181
static void
renatofilho@787
  1182
no_more_pads_cb (GstElement * element, GstDecodeBin * dbin)
renatofilho@787
  1183
{
renatofilho@787
  1184
  GstDecodeGroup *group;
renatofilho@787
  1185
renatofilho@787
  1186
  GST_LOG_OBJECT (element, "No more pads, setting current group to complete");
renatofilho@787
  1187
renatofilho@787
  1188
  /* Find the non-complete group, there should only be one */
renatofilho@787
  1189
  if (!(group = get_current_group (dbin)))
renatofilho@787
  1190
    goto no_group;
renatofilho@787
  1191
renatofilho@787
  1192
  gst_decode_group_set_complete (group);
renatofilho@787
  1193
  return;
renatofilho@787
  1194
renatofilho@787
  1195
no_group:
renatofilho@787
  1196
  {
renatofilho@787
  1197
    GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!");
renatofilho@787
  1198
    return;
renatofilho@787
  1199
  }
renatofilho@787
  1200
}
renatofilho@787
  1201
renatofilho@787
  1202
/* this function runs through the element factories and returns a list
renatofilho@787
  1203
 * of all elements that are able to sink the given caps 
renatofilho@787
  1204
 */
renatofilho@787
  1205
static GList *
renatofilho@787
  1206
find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
renatofilho@787
  1207
{
renatofilho@787
  1208
  GList *factories;
renatofilho@787
  1209
  GList *to_try = NULL;
renatofilho@787
  1210
renatofilho@787
  1211
  /* loop over all the factories */
renatofilho@787
  1212
  for (factories = decode_bin->factories; factories;
renatofilho@787
  1213
      factories = g_list_next (factories)) {
renatofilho@787
  1214
    GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
renatofilho@787
  1215
    const GList *templates;
renatofilho@787
  1216
    GList *walk;
renatofilho@787
  1217
renatofilho@787
  1218
    /* get the templates from the element factory */
renatofilho@787
  1219
    templates = gst_element_factory_get_static_pad_templates (factory);
renatofilho@787
  1220
    for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
renatofilho@787
  1221
      GstStaticPadTemplate *templ = walk->data;
renatofilho@787
  1222
renatofilho@787
  1223
      /* we only care about the sink templates */
renatofilho@787
  1224
      if (templ->direction == GST_PAD_SINK) {
renatofilho@787
  1225
        GstCaps *intersect;
renatofilho@787
  1226
        GstCaps *tmpl_caps;
renatofilho@787
  1227
renatofilho@787
  1228
        /* try to intersect the caps with the caps of the template */
renatofilho@787
  1229
        tmpl_caps = gst_static_caps_get (&templ->static_caps);
renatofilho@787
  1230
renatofilho@787
  1231
        intersect = gst_caps_intersect (caps, tmpl_caps);
renatofilho@787
  1232
        gst_caps_unref (tmpl_caps);
renatofilho@787
  1233
renatofilho@787
  1234
        /* check if the intersection is empty */
renatofilho@787
  1235
        if (!gst_caps_is_empty (intersect)) {
renatofilho@787
  1236
          /* non empty intersection, we can use this element */
renatofilho@787
  1237
          to_try = g_list_prepend (to_try, factory);
renatofilho@787
  1238
          gst_caps_unref (intersect);
renatofilho@787
  1239
          break;
renatofilho@787
  1240
        }
renatofilho@787
  1241
        gst_caps_unref (intersect);
renatofilho@787
  1242
      }
renatofilho@787
  1243
    }
renatofilho@787
  1244
  }
renatofilho@787
  1245
  to_try = g_list_reverse (to_try);
renatofilho@787
  1246
renatofilho@787
  1247
  return to_try;
renatofilho@787
  1248
}
renatofilho@787
  1249
renatofilho@787
  1250
/* Decide whether an element is a demuxer based on the 
renatofilho@787
  1251
 * klass and number/type of src pad templates it has */
renatofilho@787
  1252
static gboolean
renatofilho@787
  1253
is_demuxer_element (GstElement * srcelement)
renatofilho@787
  1254
{
renatofilho@787
  1255
  GstElementFactory *srcfactory;
renatofilho@787
  1256
  GstElementClass *elemclass;
renatofilho@787
  1257
  GList *templates, *walk;
renatofilho@787
  1258
  const gchar *klass;
renatofilho@787
  1259
  gint potential_src_pads = 0;
renatofilho@787
  1260
renatofilho@787
  1261
  srcfactory = gst_element_get_factory (srcelement);
renatofilho@787
  1262
  klass = gst_element_factory_get_klass (srcfactory);
renatofilho@787
  1263
renatofilho@787
  1264
  /* Can't be a demuxer unless it has Demux in the klass name */
renatofilho@787
  1265
  if (!strstr (klass, "Demux"))
renatofilho@787
  1266
    return FALSE;
renatofilho@787
  1267
renatofilho@787
  1268
  /* Walk the src pad templates and count how many the element
renatofilho@787
  1269
   * might produce */
renatofilho@787
  1270
  elemclass = GST_ELEMENT_GET_CLASS (srcelement);
renatofilho@787
  1271
renatofilho@787
  1272
  walk = templates = gst_element_class_get_pad_template_list (elemclass);
renatofilho@787
  1273
  while (walk != NULL) {
renatofilho@787
  1274
    GstPadTemplate *templ;
renatofilho@787
  1275
renatofilho@787
  1276
    templ = (GstPadTemplate *) walk->data;
renatofilho@787
  1277
    if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
renatofilho@787
  1278
      switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
renatofilho@787
  1279
        case GST_PAD_ALWAYS:
renatofilho@787
  1280
        case GST_PAD_SOMETIMES:
renatofilho@787
  1281
          if (strstr (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "%"))
renatofilho@787
  1282
            potential_src_pads += 2;    /* Might make multiple pads */
renatofilho@787
  1283
          else
renatofilho@787
  1284
            potential_src_pads += 1;
renatofilho@787
  1285
          break;
renatofilho@787
  1286
        case GST_PAD_REQUEST:
renatofilho@787
  1287
          potential_src_pads += 2;
renatofilho@787
  1288
          break;
renatofilho@787
  1289
      }
renatofilho@787
  1290
    }
renatofilho@787
  1291
    walk = g_list_next (walk);
renatofilho@787
  1292
  }
renatofilho@787
  1293
renatofilho@787
  1294
  if (potential_src_pads < 2)
renatofilho@787
  1295
    return FALSE;
renatofilho@787
  1296
renatofilho@787
  1297
  return TRUE;
renatofilho@787
  1298
}
renatofilho@787
  1299
renatofilho@787
  1300
/* Returns TRUE if the caps are raw, or if they are compatible with the caps 
renatofilho@787
  1301
 * specified in the 'caps' property 
renatofilho@787
  1302
 * 
renatofilho@787
  1303
 * The decodebin_lock should be taken !
renatofilho@787
  1304
 */
renatofilho@787
  1305
static gboolean
renatofilho@787
  1306
are_raw_caps (GstDecodeBin * dbin, GstCaps * caps)
renatofilho@787
  1307
{
renatofilho@787
  1308
  GstCaps *intersection;
renatofilho@787
  1309
  gboolean res;
renatofilho@787
  1310
renatofilho@787
  1311
  GST_LOG_OBJECT (dbin, "Checking with caps %" GST_PTR_FORMAT, caps);
renatofilho@787
  1312
renatofilho@787
  1313
  intersection = gst_caps_intersect (dbin->caps, caps);
renatofilho@787
  1314
renatofilho@787
  1315
  res = (!(gst_caps_is_empty (intersection)));
renatofilho@787
  1316
renatofilho@787
  1317
  gst_caps_unref (intersection);
renatofilho@787
  1318
renatofilho@787
  1319
  GST_LOG_OBJECT (dbin, "Caps are %sfinal caps", res ? "" : "not ");
renatofilho@787
  1320
renatofilho@787
  1321
  return res;
renatofilho@787
  1322
}
renatofilho@787
  1323
renatofilho@787
  1324
renatofilho@787
  1325
/****
renatofilho@787
  1326
 * GstDecodeGroup functions
renatofilho@787
  1327
 ****/
renatofilho@787
  1328
renatofilho@787
  1329
static void
renatofilho@787
  1330
multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group)
renatofilho@787
  1331
{
renatofilho@787
  1332
  GST_LOG_OBJECT (group->dbin, "multiqueue is full");
renatofilho@787
  1333
renatofilho@787
  1334
  /* if we haven't exposed the group, do it */
renatofilho@787
  1335
  DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1336
  gst_decode_group_expose (group);
renatofilho@787
  1337
  DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1338
}
renatofilho@787
  1339
renatofilho@787
  1340
static void
renatofilho@787
  1341
multi_queue_underrun_cb (GstElement * queue, GstDecodeGroup * group)
renatofilho@787
  1342
{
renatofilho@787
  1343
  GstDecodeBin *dbin = group->dbin;
renatofilho@787
  1344
renatofilho@787
  1345
  GST_LOG_OBJECT (dbin, "multiqueue is empty for group %p", group);
renatofilho@787
  1346
renatofilho@787
  1347
  /* Check if we need to activate another group */
renatofilho@787
  1348
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1349
  if ((group == dbin->activegroup) && dbin->groups) {
renatofilho@787
  1350
    GST_DEBUG_OBJECT (dbin, "Switching to new group");
renatofilho@787
  1351
    /* unexpose current active */
renatofilho@787
  1352
    gst_decode_group_hide (group);
renatofilho@787
  1353
renatofilho@787
  1354
    /* expose first group of groups */
renatofilho@787
  1355
    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
renatofilho@787
  1356
  }
renatofilho@787
  1357
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1358
}
renatofilho@787
  1359
renatofilho@787
  1360
/* gst_decode_group_new
renatofilho@787
  1361
 *
renatofilho@787
  1362
 * Creates a new GstDecodeGroup. It is up to the caller to add it to the list
renatofilho@787
  1363
 * of groups.
renatofilho@787
  1364
 */
renatofilho@787
  1365
static GstDecodeGroup *
renatofilho@787
  1366
gst_decode_group_new (GstDecodeBin * dbin)
renatofilho@787
  1367
{
renatofilho@787
  1368
  GstDecodeGroup *group;
renatofilho@787
  1369
  GstElement *mq;
renatofilho@787
  1370
renatofilho@787
  1371
  GST_LOG_OBJECT (dbin, "Creating new group");
renatofilho@787
  1372
renatofilho@787
  1373
  if (!(mq = gst_element_factory_make ("multiqueue", NULL))) {
renatofilho@787
  1374
    GST_WARNING ("Couldn't create multiqueue element");
renatofilho@787
  1375
    return NULL;
renatofilho@787
  1376
  }
renatofilho@787
  1377
renatofilho@787
  1378
  g_object_set (G_OBJECT (mq),
renatofilho@787
  1379
      "max-size-bytes", 2 * 1024 * 1024,
renatofilho@787
  1380
      "max-size-time", 5 * GST_SECOND, "max-size-buffers", 0, NULL);
renatofilho@787
  1381
renatofilho@787
  1382
  group = g_new0 (GstDecodeGroup, 1);
renatofilho@787
  1383
  group->lock = g_mutex_new ();
renatofilho@787
  1384
  group->dbin = dbin;
renatofilho@787
  1385
  group->multiqueue = mq;
renatofilho@787
  1386
  group->exposed = FALSE;
renatofilho@787
  1387
  group->drained = FALSE;
renatofilho@787
  1388
  group->blocked = FALSE;
renatofilho@787
  1389
  group->complete = FALSE;
renatofilho@787
  1390
  group->endpads = NULL;
renatofilho@787
  1391
renatofilho@787
  1392
  group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun",
renatofilho@787
  1393
      G_CALLBACK (multi_queue_overrun_cb), group);
renatofilho@787
  1394
  group->underrunsig = g_signal_connect (G_OBJECT (mq), "underrun",
renatofilho@787
  1395
      G_CALLBACK (multi_queue_underrun_cb), group);
renatofilho@787
  1396
renatofilho@787
  1397
  gst_bin_add (GST_BIN (dbin), group->multiqueue);
renatofilho@787
  1398
  gst_element_set_state (group->multiqueue, GST_STATE_PAUSED);
renatofilho@787
  1399
renatofilho@787
  1400
  GST_LOG_OBJECT (dbin, "Returning new group %p", group);
renatofilho@787
  1401
renatofilho@787
  1402
  return group;
renatofilho@787
  1403
}
renatofilho@787
  1404
renatofilho@787
  1405
/** get_current_group:
renatofilho@787
  1406
 *
renatofilho@787
  1407
 * Returns the current non-completed group.
renatofilho@787
  1408
 *
renatofilho@787
  1409
 * Returns NULL if no groups are available, or all groups are completed.
renatofilho@787
  1410
 */
renatofilho@787
  1411
static GstDecodeGroup *
renatofilho@787
  1412
get_current_group (GstDecodeBin * dbin)
renatofilho@787
  1413
{
renatofilho@787
  1414
  GList *tmp;
renatofilho@787
  1415
  GstDecodeGroup *group = NULL;
renatofilho@787
  1416
renatofilho@787
  1417
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1418
  for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1419
    GstDecodeGroup *this = (GstDecodeGroup *) tmp->data;
renatofilho@787
  1420
renatofilho@787
  1421
    GST_LOG_OBJECT (dbin, "group %p, complete:%d", this, this->complete);
renatofilho@787
  1422
renatofilho@787
  1423
    if (!this->complete) {
renatofilho@787
  1424
      group = this;
renatofilho@787
  1425
      break;
renatofilho@787
  1426
    }
renatofilho@787
  1427
  }
renatofilho@787
  1428
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1429
renatofilho@787
  1430
  GST_LOG_OBJECT (dbin, "Returning group %p", group);
renatofilho@787
  1431
renatofilho@787
  1432
  return group;
renatofilho@787
  1433
}
renatofilho@787
  1434
renatofilho@787
  1435
static gboolean
renatofilho@787
  1436
group_demuxer_event_probe (GstPad * pad, GstEvent * event,
renatofilho@787
  1437
    GstDecodeGroup * group)
renatofilho@787
  1438
{
renatofilho@787
  1439
  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
renatofilho@787
  1440
    GST_DEBUG_OBJECT (group->dbin,
renatofilho@787
  1441
        "Got EOS on group input pads, exposing group if it wasn't before");
renatofilho@787
  1442
    DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1443
    gst_decode_group_expose (group);
renatofilho@787
  1444
    DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1445
  }
renatofilho@787
  1446
  return TRUE;
renatofilho@787
  1447
}
renatofilho@787
  1448
renatofilho@787
  1449
/* gst_decode_group_control_demuxer_pad
renatofilho@787
  1450
 *
renatofilho@787
  1451
 * Adds a new demuxer srcpad to the given group.
renatofilho@787
  1452
 *
renatofilho@787
  1453
 * Returns the srcpad of the multiqueue corresponding the given pad.
renatofilho@787
  1454
 * Returns NULL if there was an error.
renatofilho@787
  1455
 */
renatofilho@787
  1456
static GstPad *
renatofilho@787
  1457
gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad)
renatofilho@787
  1458
{
renatofilho@787
  1459
  GstPad *srcpad, *sinkpad;
renatofilho@787
  1460
  gchar *nb, *sinkname, *srcname;
renatofilho@787
  1461
renatofilho@787
  1462
  GST_LOG ("group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
renatofilho@787
  1463
renatofilho@787
  1464
  srcpad = NULL;
renatofilho@787
  1465
renatofilho@787
  1466
  if (!(sinkpad = gst_element_get_pad (group->multiqueue, "sink%d"))) {
renatofilho@787
  1467
    GST_ERROR ("Couldn't get sinkpad from multiqueue");
renatofilho@787
  1468
    return NULL;
renatofilho@787
  1469
  }
renatofilho@787
  1470
renatofilho@787
  1471
  if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
renatofilho@787
  1472
    GST_ERROR ("Couldn't link demuxer and multiqueue");
renatofilho@787
  1473
    goto beach;
renatofilho@787
  1474
  }
renatofilho@787
  1475
renatofilho@787
  1476
  sinkname = gst_pad_get_name (sinkpad);
renatofilho@787
  1477
  nb = sinkname + 4;
renatofilho@787
  1478
  srcname = g_strdup_printf ("src%s", nb);
renatofilho@787
  1479
  g_free (sinkname);
renatofilho@787
  1480
renatofilho@787
  1481
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1482
renatofilho@787
  1483
  if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) {
renatofilho@787
  1484
    GST_ERROR ("Couldn't get srcpad %s from multiqueue", srcname);
renatofilho@787
  1485
    goto chiringuito;
renatofilho@787
  1486
  }
renatofilho@787
  1487
renatofilho@787
  1488
  /* connect event handler on pad to intercept EOS events */
renatofilho@787
  1489
  gst_pad_add_event_probe (pad, G_CALLBACK (group_demuxer_event_probe), group);
renatofilho@787
  1490
renatofilho@787
  1491
chiringuito:
renatofilho@787
  1492
  g_free (srcname);
renatofilho@787
  1493
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1494
renatofilho@787
  1495
beach:
renatofilho@787
  1496
  gst_object_unref (sinkpad);
renatofilho@787
  1497
  return srcpad;
renatofilho@787
  1498
}
renatofilho@787
  1499
renatofilho@787
  1500
static gboolean
renatofilho@787
  1501
gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad)
renatofilho@787
  1502
{
renatofilho@787
  1503
  GstDecodePad *dpad;
renatofilho@787
  1504
renatofilho@787
  1505
  g_return_val_if_fail (group != NULL, FALSE);
renatofilho@787
  1506
renatofilho@787
  1507
  GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
renatofilho@787
  1508
renatofilho@787
  1509
  /* FIXME : check if pad is already controlled */
renatofilho@787
  1510
renatofilho@787
  1511
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1512
renatofilho@787
  1513
  /* Create GstDecodePad for the pad */
renatofilho@787
  1514
  dpad = gst_decode_pad_new (group, pad, TRUE);
renatofilho@787
  1515
renatofilho@787
  1516
  group->endpads = g_list_append (group->endpads, dpad);
renatofilho@787
  1517
renatofilho@787
  1518
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1519
renatofilho@787
  1520
  return TRUE;
renatofilho@787
  1521
}
renatofilho@787
  1522
renatofilho@787
  1523
/* gst_decode_group_check_if_blocked:
renatofilho@787
  1524
 *
renatofilho@787
  1525
 * Call this when one of the pads blocked status has changed.
renatofilho@787
  1526
 * If the group is complete and blocked, the group will be marked as blocked
renatofilho@787
  1527
 * and will ghost/expose all pads on decodebin if the group is the current one.
renatofilho@787
  1528
 *
renatofilho@787
  1529
 * Call with the group lock taken ! MT safe
renatofilho@787
  1530
 */
renatofilho@787
  1531
static void
renatofilho@787
  1532
gst_decode_group_check_if_blocked (GstDecodeGroup * group)
renatofilho@787
  1533
{
renatofilho@787
  1534
  GList *tmp;
renatofilho@787
  1535
  gboolean blocked = TRUE;
renatofilho@787
  1536
renatofilho@787
  1537
  GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d",
renatofilho@787
  1538
      group, group->complete, group->nbdynamic);
renatofilho@787
  1539
renatofilho@787
  1540
  /* 1. don't do anything if group is not complete */
renatofilho@787
  1541
  if (!group->complete || group->nbdynamic) {
renatofilho@787
  1542
    GST_DEBUG_OBJECT (group->dbin, "Group isn't complete yet");
renatofilho@787
  1543
    return;
renatofilho@787
  1544
  }
renatofilho@787
  1545
renatofilho@787
  1546
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1547
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1548
renatofilho@787
  1549
    if (!dpad->blocked) {
renatofilho@787
  1550
      blocked = FALSE;
renatofilho@787
  1551
      break;
renatofilho@787
  1552
    }
renatofilho@787
  1553
  }
renatofilho@787
  1554
renatofilho@787
  1555
  /* 2. Update status of group */
renatofilho@787
  1556
  group->blocked = blocked;
renatofilho@787
  1557
  GST_LOG ("group is blocked:%d", blocked);
renatofilho@787
  1558
renatofilho@787
  1559
  /* 3. don't do anything if not blocked completely */
renatofilho@787
  1560
  if (!blocked)
renatofilho@787
  1561
    return;
renatofilho@787
  1562
renatofilho@787
  1563
  /* 4. if we're the current group, expose pads */
renatofilho@787
  1564
  DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1565
  if (!gst_decode_group_expose (group))
renatofilho@787
  1566
    GST_WARNING_OBJECT (group->dbin, "Couldn't expose group");
renatofilho@787
  1567
  DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1568
}
renatofilho@787
  1569
renatofilho@787
  1570
static void
renatofilho@787
  1571
gst_decode_group_check_if_drained (GstDecodeGroup * group)
renatofilho@787
  1572
{
renatofilho@787
  1573
  GList *tmp;
renatofilho@787
  1574
  GstDecodeBin *dbin = group->dbin;
renatofilho@787
  1575
  gboolean drained = TRUE;
renatofilho@787
  1576
renatofilho@787
  1577
  GST_LOG ("group : %p", group);
renatofilho@787
  1578
renatofilho@787
  1579
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1580
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1581
renatofilho@787
  1582
    GST_LOG ("testing dpad %p", dpad);
renatofilho@787
  1583
renatofilho@787
  1584
    if (!dpad->drained) {
renatofilho@787
  1585
      drained = FALSE;
renatofilho@787
  1586
      break;
renatofilho@787
  1587
    }
renatofilho@787
  1588
  }
renatofilho@787
  1589
renatofilho@787
  1590
  group->drained = drained;
renatofilho@787
  1591
  GST_LOG ("group is drained");
renatofilho@787
  1592
renatofilho@787
  1593
  if (!drained)
renatofilho@787
  1594
    return;
renatofilho@787
  1595
renatofilho@787
  1596
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1597
  if ((group == dbin->activegroup) && dbin->groups) {
renatofilho@787
  1598
    GST_DEBUG_OBJECT (dbin, "Switching to new group");
renatofilho@787
  1599
renatofilho@787
  1600
    gst_decode_group_hide (group);
renatofilho@787
  1601
renatofilho@787
  1602
    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
renatofilho@787
  1603
  }
renatofilho@787
  1604
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1605
}
renatofilho@787
  1606
renatofilho@787
  1607
/* sort_end_pads:
renatofilho@787
  1608
 * GCompareFunc to use with lists of GstPad.
renatofilho@787
  1609
 * Sorts pads by mime type.
renatofilho@787
  1610
 * First video (raw, then non-raw), then audio (raw, then non-raw),
renatofilho@787
  1611
 * then others.
renatofilho@787
  1612
 *
renatofilho@787
  1613
 * Return: negative if a<b, 0 if a==b, positive if a>b
renatofilho@787
  1614
 */
renatofilho@787
  1615
renatofilho@787
  1616
static gint
renatofilho@787
  1617
sort_end_pads (GstDecodePad * da, GstDecodePad * db)
renatofilho@787
  1618
{
renatofilho@787
  1619
  GstPad *a, *b;
renatofilho@787
  1620
  gint va, vb;
renatofilho@787
  1621
  GstCaps *capsa, *capsb;
renatofilho@787
  1622
  GstStructure *sa, *sb;
renatofilho@787
  1623
  const gchar *namea, *nameb;
renatofilho@787
  1624
renatofilho@787
  1625
  a = da->pad;
renatofilho@787
  1626
  b = db->pad;
renatofilho@787
  1627
renatofilho@787
  1628
  capsa = gst_pad_get_caps (a);
renatofilho@787
  1629
  capsb = gst_pad_get_caps (b);
renatofilho@787
  1630
renatofilho@787
  1631
  sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
renatofilho@787
  1632
  sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
renatofilho@787
  1633
renatofilho@787
  1634
  namea = gst_structure_get_name (sa);
renatofilho@787
  1635
  nameb = gst_structure_get_name (sb);
renatofilho@787
  1636
renatofilho@787
  1637
  if (g_strrstr (namea, "video/x-raw-"))
renatofilho@787
  1638
    va = 0;
renatofilho@787
  1639
  else if (g_strrstr (namea, "video/"))
renatofilho@787
  1640
    va = 1;
renatofilho@787
  1641
  else if (g_strrstr (namea, "audio/x-raw"))
renatofilho@787
  1642
    va = 2;
renatofilho@787
  1643
  else if (g_strrstr (namea, "audio/"))
renatofilho@787
  1644
    va = 3;
renatofilho@787
  1645
  else
renatofilho@787
  1646
    va = 4;
renatofilho@787
  1647
renatofilho@787
  1648
  if (g_strrstr (nameb, "video/x-raw-"))
renatofilho@787
  1649
    vb = 0;
renatofilho@787
  1650
  else if (g_strrstr (nameb, "video/"))
renatofilho@787
  1651
    vb = 1;
renatofilho@787
  1652
  else if (g_strrstr (nameb, "audio/x-raw"))
renatofilho@787
  1653
    vb = 2;
renatofilho@787
  1654
  else if (g_strrstr (nameb, "audio/"))
renatofilho@787
  1655
    vb = 3;
renatofilho@787
  1656
  else
renatofilho@787
  1657
    vb = 4;
renatofilho@787
  1658
renatofilho@787
  1659
  gst_caps_unref (capsa);
renatofilho@787
  1660
  gst_caps_unref (capsb);
renatofilho@787
  1661
renatofilho@787
  1662
  return va - vb;
renatofilho@787
  1663
}
renatofilho@787
  1664
renatofilho@787
  1665
/* gst_decode_group_expose:
renatofilho@787
  1666
 *
renatofilho@787
  1667
 * Expose this group's pads.
renatofilho@787
  1668
 *
renatofilho@787
  1669
 * Not MT safe, please take the group lock
renatofilho@787
  1670
 */
renatofilho@787
  1671
renatofilho@787
  1672
static gboolean
renatofilho@787
  1673
gst_decode_group_expose (GstDecodeGroup * group)
renatofilho@787
  1674
{
renatofilho@787
  1675
  GList *tmp;
renatofilho@787
  1676
  GList *next = NULL;
renatofilho@787
  1677
renatofilho@787
  1678
  if (group->dbin->activegroup) {
renatofilho@787
  1679
    GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed");
renatofilho@787
  1680
    return TRUE;
renatofilho@787
  1681
  }
renatofilho@787
  1682
renatofilho@787
  1683
  if (group->dbin->activegroup == group) {
renatofilho@787
  1684
    GST_WARNING ("Group %p is already exposed", group);
renatofilho@787
  1685
    return TRUE;
renatofilho@787
  1686
  }
renatofilho@787
  1687
renatofilho@787
  1688
  if (!group->dbin->groups
renatofilho@787
  1689
      || (group != (GstDecodeGroup *) group->dbin->groups->data)) {
renatofilho@787
  1690
    GST_WARNING ("Group %p is not the first group to expose", group);
renatofilho@787
  1691
    return FALSE;
renatofilho@787
  1692
  }
renatofilho@787
  1693
renatofilho@787
  1694
  if (group->nbdynamic) {
renatofilho@787
  1695
    GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet",
renatofilho@787
  1696
        group, group->nbdynamic);
renatofilho@787
  1697
    return FALSE;
renatofilho@787
  1698
  }
renatofilho@787
  1699
renatofilho@787
  1700
  GST_LOG ("Exposing group %p", group);
renatofilho@787
  1701
renatofilho@787
  1702
  /* re-order pads : video, then audio, then others */
renatofilho@787
  1703
  group->endpads = g_list_sort (group->endpads, (GCompareFunc) sort_end_pads);
renatofilho@787
  1704
renatofilho@787
  1705
  /* Expose pads */
renatofilho@787
  1706
renatofilho@787
  1707
  for (tmp = group->endpads; tmp; tmp = next) {
renatofilho@787
  1708
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1709
    gchar *padname;
renatofilho@787
  1710
    GstPad *ghost;
renatofilho@787
  1711
renatofilho@787
  1712
    next = g_list_next (tmp);
renatofilho@787
  1713
renatofilho@787
  1714
    /* 1. ghost pad */
renatofilho@787
  1715
    padname = g_strdup_printf ("src%d", group->dbin->nbpads);
renatofilho@787
  1716
    group->dbin->nbpads++;
renatofilho@787
  1717
renatofilho@787
  1718
    GST_LOG_OBJECT (group->dbin, "About to expose pad %s:%s",
renatofilho@787
  1719
        GST_DEBUG_PAD_NAME (dpad->pad));
renatofilho@787
  1720
renatofilho@787
  1721
    ghost = gst_ghost_pad_new (padname, dpad->pad);
renatofilho@787
  1722
    gst_pad_set_active (ghost, TRUE);
renatofilho@787
  1723
    gst_element_add_pad (GST_ELEMENT (group->dbin), ghost);
renatofilho@787
  1724
    group->ghosts = g_list_append (group->ghosts, ghost);
renatofilho@787
  1725
renatofilho@787
  1726
    g_free (padname);
renatofilho@787
  1727
renatofilho@787
  1728
    /* 2. emit signal */
renatofilho@787
  1729
    GST_DEBUG_OBJECT (group->dbin, "emitting new-decoded-pad");
renatofilho@787
  1730
    g_signal_emit (G_OBJECT (group->dbin),
renatofilho@787
  1731
        gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost,
renatofilho@787
  1732
        (next == NULL));
renatofilho@787
  1733
    GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad");
renatofilho@787
  1734
renatofilho@787
  1735
    /* 3. Unblock internal  pad */
renatofilho@787
  1736
    GST_DEBUG_OBJECT (dpad->pad, "unblocking");
renatofilho@787
  1737
    gst_pad_set_blocked_async (dpad->pad, FALSE,
renatofilho@787
  1738
        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
renatofilho@787
  1739
    GST_DEBUG_OBJECT (dpad->pad, "unblocked");
renatofilho@787
  1740
renatofilho@787
  1741
  }
renatofilho@787
  1742
renatofilho@787
  1743
  group->dbin->activegroup = group;
renatofilho@787
  1744
renatofilho@787
  1745
  /* pop off the first group */
renatofilho@787
  1746
  group->dbin->groups =
renatofilho@787
  1747
      g_list_delete_link (group->dbin->groups, group->dbin->groups);
renatofilho@787
  1748
renatofilho@787
  1749
  remove_fakesink (group->dbin);
renatofilho@787
  1750
renatofilho@787
  1751
  group->exposed = TRUE;
renatofilho@787
  1752
renatofilho@787
  1753
  GST_LOG_OBJECT (group->dbin, "signalling no-more-pads");
renatofilho@787
  1754
  gst_element_no_more_pads (GST_ELEMENT (group->dbin));
renatofilho@787
  1755
renatofilho@787
  1756
  GST_LOG_OBJECT (group->dbin, "Group %p exposed", group);
renatofilho@787
  1757
  return TRUE;
renatofilho@787
  1758
}
renatofilho@787
  1759
renatofilho@787
  1760
static void
renatofilho@787
  1761
gst_decode_group_hide (GstDecodeGroup * group)
renatofilho@787
  1762
{
renatofilho@787
  1763
  GList *tmp;
renatofilho@787
  1764
renatofilho@787
  1765
  GST_LOG ("Hiding group %p", group);
renatofilho@787
  1766
renatofilho@787
  1767
  if (group != group->dbin->activegroup) {
renatofilho@787
  1768
    GST_WARNING ("This group is not the active one, aborting");
renatofilho@787
  1769
    return;
renatofilho@787
  1770
  }
renatofilho@787
  1771
renatofilho@787
  1772
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1773
renatofilho@787
  1774
  /* Remove ghost pads */
renatofilho@787
  1775
  for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
renatofilho@787
  1776
    gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
renatofilho@787
  1777
renatofilho@787
  1778
  g_list_free (group->ghosts);
renatofilho@787
  1779
  group->ghosts = NULL;
renatofilho@787
  1780
renatofilho@787
  1781
  group->exposed = FALSE;
renatofilho@787
  1782
renatofilho@787
  1783
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1784
renatofilho@787
  1785
  group->dbin->activegroup = NULL;
renatofilho@787
  1786
  group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group);
renatofilho@787
  1787
}
renatofilho@787
  1788
renatofilho@787
  1789
static void
renatofilho@787
  1790
deactivate_free_recursive (GstDecodeGroup * group, GstElement * element)
renatofilho@787
  1791
{
renatofilho@787
  1792
  GstIterator *it;
renatofilho@787
  1793
  GstIteratorResult res;
renatofilho@787
  1794
  gpointer point;
renatofilho@787
  1795
renatofilho@787
  1796
  GST_LOG ("element:%s", GST_ELEMENT_NAME (element));
renatofilho@787
  1797
renatofilho@787
  1798
  /* call on downstream elements */
renatofilho@787
  1799
  it = gst_element_iterate_src_pads (element);
renatofilho@787
  1800
renatofilho@787
  1801
restart:
renatofilho@787
  1802
renatofilho@787
  1803
  while (1) {
renatofilho@787
  1804
    res = gst_iterator_next (it, &point);
renatofilho@787
  1805
    switch (res) {
renatofilho@787
  1806
      case GST_ITERATOR_DONE:
renatofilho@787
  1807
        goto done;
renatofilho@787
  1808
      case GST_ITERATOR_RESYNC:
renatofilho@787
  1809
        gst_iterator_resync (it);
renatofilho@787
  1810
        goto restart;
renatofilho@787
  1811
      case GST_ITERATOR_ERROR:
renatofilho@787
  1812
      {
renatofilho@787
  1813
        GST_WARNING ("Had an error while iterating source pads of element: %s",
renatofilho@787
  1814
            GST_ELEMENT_NAME (element));
renatofilho@787
  1815
        goto beach;
renatofilho@787
  1816
      }
renatofilho@787
  1817
      case GST_ITERATOR_OK:
renatofilho@787
  1818
      {
renatofilho@787
  1819
        GstPad *pad = GST_PAD (point);
renatofilho@787
  1820
        GstPad *peerpad = NULL;
renatofilho@787
  1821
renatofilho@787
  1822
        if ((peerpad = gst_pad_get_peer (pad))) {
renatofilho@787
  1823
          GstObject *parent = gst_pad_get_parent (peerpad);
renatofilho@787
  1824
renatofilho@787
  1825
          if (parent && GST_IS_ELEMENT (parent))
renatofilho@787
  1826
            deactivate_free_recursive (group, GST_ELEMENT (parent));
renatofilho@787
  1827
          if (parent)
renatofilho@787
  1828
            gst_object_unref (parent);
renatofilho@787
  1829
        }
renatofilho@787
  1830
      }
renatofilho@787
  1831
        break;
renatofilho@787
  1832
      default:
renatofilho@787
  1833
        break;
renatofilho@787
  1834
    }
renatofilho@787
  1835
  }
renatofilho@787
  1836
renatofilho@787
  1837
done:
renatofilho@787
  1838
  gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
  1839
  gst_bin_remove (GST_BIN (group->dbin), element);
renatofilho@787
  1840
renatofilho@787
  1841
beach:
renatofilho@787
  1842
  gst_iterator_free (it);
renatofilho@787
  1843
renatofilho@787
  1844
  return;
renatofilho@787
  1845
}
renatofilho@787
  1846
renatofilho@787
  1847
static void
renatofilho@787
  1848
gst_decode_group_free (GstDecodeGroup * group)
renatofilho@787
  1849
{
renatofilho@787
  1850
  GList *tmp;
renatofilho@787
  1851
renatofilho@787
  1852
  GST_LOG ("group %p", group);
renatofilho@787
  1853
renatofilho@787
  1854
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1855
  /* Clear all GstDecodePad */
renatofilho@787
  1856
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1857
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1858
renatofilho@787
  1859
    g_free (dpad);
renatofilho@787
  1860
  }
renatofilho@787
  1861
  g_list_free (group->endpads);
renatofilho@787
  1862
  group->endpads = NULL;
renatofilho@787
  1863
renatofilho@787
  1864
  /* disconnect signal handlers on multiqueue */
renatofilho@787
  1865
  g_signal_handler_disconnect (group->multiqueue, group->underrunsig);
renatofilho@787
  1866
  g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
renatofilho@787
  1867
renatofilho@787
  1868
  /* remove all elements */
renatofilho@787
  1869
  deactivate_free_recursive (group, group->multiqueue);
renatofilho@787
  1870
renatofilho@787
  1871
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1872
renatofilho@787
  1873
  g_mutex_free (group->lock);
renatofilho@787
  1874
  g_free (group);
renatofilho@787
  1875
}
renatofilho@787
  1876
renatofilho@787
  1877
/* gst_decode_group_set_complete:
renatofilho@787
  1878
 *
renatofilho@787
  1879
 * Mark the group as complete. This means no more streams will be controlled
renatofilho@787
  1880
 * through this group.
renatofilho@787
  1881
 *
renatofilho@787
  1882
 * MT safe
renatofilho@787
  1883
 */
renatofilho@787
  1884
static void
renatofilho@787
  1885
gst_decode_group_set_complete (GstDecodeGroup * group)
renatofilho@787
  1886
{
renatofilho@787
  1887
  GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group);
renatofilho@787
  1888
renatofilho@787
  1889
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1890
  group->complete = TRUE;
renatofilho@787
  1891
  gst_decode_group_check_if_blocked (group);
renatofilho@787
  1892
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1893
}
renatofilho@787
  1894
renatofilho@787
  1895
renatofilho@787
  1896
renatofilho@787
  1897
/*************************
renatofilho@787
  1898
 * GstDecodePad functions
renatofilho@787
  1899
 *************************/
renatofilho@787
  1900
renatofilho@787
  1901
static void
renatofilho@787
  1902
source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
renatofilho@787
  1903
{
renatofilho@787
  1904
  GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p",
renatofilho@787
  1905
      blocked, dpad, dpad->group);
renatofilho@787
  1906
renatofilho@787
  1907
  /* Update this GstDecodePad status */
renatofilho@787
  1908
  dpad->blocked = blocked;
renatofilho@787
  1909
renatofilho@787
  1910
  if (blocked) {
renatofilho@787
  1911
    GROUP_MUTEX_LOCK (dpad->group);
renatofilho@787
  1912
    gst_decode_group_check_if_blocked (dpad->group);
renatofilho@787
  1913
    GROUP_MUTEX_UNLOCK (dpad->group);
renatofilho@787
  1914
  }
renatofilho@787
  1915
}
renatofilho@787
  1916
renatofilho@787
  1917
static gboolean
renatofilho@787
  1918
source_pad_event_probe (GstPad * pad, GstEvent * event, GstDecodePad * dpad)
renatofilho@787
  1919
{
renatofilho@787
  1920
  GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
renatofilho@787
  1921
renatofilho@787
  1922
  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
renatofilho@787
  1923
    /* Set our pad as drained */
renatofilho@787
  1924
    dpad->drained = TRUE;
renatofilho@787
  1925
renatofilho@787
  1926
    /* Check if all pads are drained */
renatofilho@787
  1927
    gst_decode_group_check_if_drained (dpad->group);
renatofilho@787
  1928
  }
renatofilho@787
  1929
renatofilho@787
  1930
  return TRUE;
renatofilho@787
  1931
}
renatofilho@787
  1932
renatofilho@787
  1933
/*gst_decode_pad_new:
renatofilho@787
  1934
 *
renatofilho@787
  1935
 * Creates a new GstDecodePad for the given pad.
renatofilho@787
  1936
 * If block is TRUE, Sets the pad blocking asynchronously
renatofilho@787
  1937
 */
renatofilho@787
  1938
renatofilho@787
  1939
static GstDecodePad *
renatofilho@787
  1940
gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block)
renatofilho@787
  1941
{
renatofilho@787
  1942
  GstDecodePad *dpad;
renatofilho@787
  1943
renatofilho@787
  1944
  dpad = g_new0 (GstDecodePad, 1);
renatofilho@787
  1945
  dpad->pad = pad;
renatofilho@787
  1946
  dpad->group = group;
renatofilho@787
  1947
  dpad->blocked = FALSE;
renatofilho@787
  1948
  dpad->drained = TRUE;
renatofilho@787
  1949
renatofilho@787
  1950
  if (block)
renatofilho@787
  1951
    gst_pad_set_blocked_async (pad, TRUE,
renatofilho@787
  1952
        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
renatofilho@787
  1953
  gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), dpad);
renatofilho@787
  1954
  return dpad;
renatofilho@787
  1955
}
renatofilho@787
  1956
renatofilho@787
  1957
renatofilho@787
  1958
/*****
renatofilho@787
  1959
 * Element add/remove
renatofilho@787
  1960
 *****/
renatofilho@787
  1961
renatofilho@787
  1962
/*
renatofilho@787
  1963
 * add_fakesink / remove_fakesink
renatofilho@787
  1964
 *
renatofilho@787
  1965
 * We use a sink so that the parent ::change_state returns GST_STATE_CHANGE_ASYNC
renatofilho@787
  1966
 * when that sink is present (since it's not connected to anything it will 
renatofilho@787
  1967
 * always return GST_STATE_CHANGE_ASYNC).
renatofilho@787
  1968
 *
renatofilho@787
  1969
 * But this is an ugly way of achieving this goal.
renatofilho@787
  1970
 * Ideally, we shouldn't use a sink and just return GST_STATE_CHANGE_ASYNC in
renatofilho@787
  1971
 * our ::change_state if we have not exposed the active group.
renatofilho@787
  1972
 * We also need to override ::get_state to fake the asynchronous behaviour.
renatofilho@787
  1973
 * Once the active group is exposed, we would then post a
renatofilho@787
  1974
 * GST_MESSAGE_STATE_DIRTY and return GST_STATE_CHANGE_SUCCESS (which will call
renatofilho@787
  1975
 * ::get_state .
renatofilho@787
  1976
 */
renatofilho@787
  1977
renatofilho@787
  1978
static gboolean
renatofilho@787
  1979
add_fakesink (GstDecodeBin * decode_bin)
renatofilho@787
  1980
{
renatofilho@787
  1981
  GST_DEBUG_OBJECT (decode_bin, "Adding the fakesink");
renatofilho@787
  1982
renatofilho@787
  1983
  if (decode_bin->fakesink)
renatofilho@787
  1984
    return TRUE;
renatofilho@787
  1985
renatofilho@787
  1986
  decode_bin->fakesink =
renatofilho@787
  1987
      gst_element_factory_make ("fakesink", "async-fakesink");
renatofilho@787
  1988
  if (!decode_bin->fakesink)
renatofilho@787
  1989
    goto no_fakesink;
renatofilho@787
  1990
renatofilho@787
  1991
  /* hacky, remove sink flag, we don't want our decodebin to become a sink
renatofilho@787
  1992
   * just because we add a fakesink element to make us ASYNC */
renatofilho@787
  1993
  GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
renatofilho@787
  1994
renatofilho@787
  1995
  if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink))
renatofilho@787
  1996
    goto could_not_add;
renatofilho@787
  1997
renatofilho@787
  1998
  return TRUE;
renatofilho@787
  1999
renatofilho@787
  2000
  /* ERRORS */
renatofilho@787
  2001
no_fakesink:
renatofilho@787
  2002
  {
renatofilho@787
  2003
    g_warning ("can't find fakesink element, decodebin will not work");
renatofilho@787
  2004
    return FALSE;
renatofilho@787
  2005
  }
renatofilho@787
  2006
could_not_add:
renatofilho@787
  2007
  {
renatofilho@787
  2008
    g_warning ("Could not add fakesink to decodebin, decodebin will not work");
renatofilho@787
  2009
    gst_object_unref (decode_bin->fakesink);
renatofilho@787
  2010
    decode_bin->fakesink = NULL;
renatofilho@787
  2011
    return FALSE;
renatofilho@787
  2012
  }
renatofilho@787
  2013
}
renatofilho@787
  2014
renatofilho@787
  2015
static void
renatofilho@787
  2016
remove_fakesink (GstDecodeBin * decode_bin)
renatofilho@787
  2017
{
renatofilho@787
  2018
  if (decode_bin->fakesink == NULL)
renatofilho@787
  2019
    return;
renatofilho@787
  2020
renatofilho@787
  2021
  GST_DEBUG_OBJECT (decode_bin, "Removing the fakesink");
renatofilho@787
  2022
renatofilho@787
  2023
  gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
renatofilho@787
  2024
  gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
renatofilho@787
  2025
  decode_bin->fakesink = NULL;
renatofilho@787
  2026
renatofilho@787
  2027
  gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
renatofilho@787
  2028
      gst_message_new_state_dirty (GST_OBJECT_CAST (decode_bin)));
renatofilho@787
  2029
}
renatofilho@787
  2030
renatofilho@787
  2031
/*****
renatofilho@787
  2032
 * convenience functions
renatofilho@787
  2033
 *****/
renatofilho@787
  2034
renatofilho@787
  2035
/* find_sink_pad
renatofilho@787
  2036
 *
renatofilho@787
  2037
 * Returns the first sink pad of the given element, or NULL if it doesn't have
renatofilho@787
  2038
 * any.
renatofilho@787
  2039
 */
renatofilho@787
  2040
renatofilho@787
  2041
static GstPad *
renatofilho@787
  2042
find_sink_pad (GstElement * element)
renatofilho@787
  2043
{
renatofilho@787
  2044
  GstIterator *it;
renatofilho@787
  2045
  GstPad *pad = NULL;
renatofilho@787
  2046
  gpointer point;
renatofilho@787
  2047
renatofilho@787
  2048
  it = gst_element_iterate_sink_pads (element);
renatofilho@787
  2049
renatofilho@787
  2050
  if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
renatofilho@787
  2051
    pad = (GstPad *) point;
renatofilho@787
  2052
renatofilho@787
  2053
  gst_iterator_free (it);
renatofilho@787
  2054
renatofilho@787
  2055
  return pad;
renatofilho@787
  2056
}
renatofilho@787
  2057
renatofilho@787
  2058
static GstStateChangeReturn
renatofilho@787
  2059
gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
renatofilho@787
  2060
{
renatofilho@787
  2061
  GstStateChangeReturn ret;
renatofilho@787
  2062
  GstDecodeBin *dbin = GST_DECODE_BIN (element);
renatofilho@787
  2063
renatofilho@787
  2064
  switch (transition) {
renatofilho@787
  2065
    case GST_STATE_CHANGE_NULL_TO_READY:
renatofilho@787
  2066
      if (dbin->typefind == NULL)
renatofilho@787
  2067
        goto missing_typefind;
renatofilho@787
  2068
      break;
renatofilho@787
  2069
    case GST_STATE_CHANGE_READY_TO_PAUSED:{
renatofilho@787
  2070
      if (!add_fakesink (dbin))
renatofilho@787
  2071
        goto missing_fakesink;
renatofilho@787
  2072
      break;
renatofilho@787
  2073
    }
renatofilho@787
  2074
    default:
renatofilho@787
  2075
      break;
renatofilho@787
  2076
  }
renatofilho@787
  2077
renatofilho@787
  2078
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
renatofilho@787
  2079
renatofilho@787
  2080
  /* FIXME : put some cleanup functions here.. if needed */
renatofilho@787
  2081
renatofilho@787
  2082
  return ret;
renatofilho@787
  2083
renatofilho@787
  2084
/* ERRORS */
renatofilho@787
  2085
missing_typefind:
renatofilho@787
  2086
  {
renatofilho@787
  2087
    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
renatofilho@787
  2088
    return GST_STATE_CHANGE_FAILURE;
renatofilho@787
  2089
  }
renatofilho@787
  2090
missing_fakesink:
renatofilho@787
  2091
  {
renatofilho@787
  2092
    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
renatofilho@787
  2093
    return GST_STATE_CHANGE_FAILURE;
renatofilho@787
  2094
  }
renatofilho@787
  2095
}
renatofilho@787
  2096
renatofilho@787
  2097
static gboolean
renatofilho@787
  2098
plugin_init (GstPlugin * plugin)
renatofilho@787
  2099
{
renatofilho@787
  2100
  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
renatofilho@787
  2101
      "decoder bin");
renatofilho@787
  2102
renatofilho@787
  2103
  return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
renatofilho@787
  2104
      GST_TYPE_DECODE_BIN);
renatofilho@787
  2105
}
renatofilho@787
  2106
renatofilho@787
  2107
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
renatofilho@787
  2108
    GST_VERSION_MINOR,
renatofilho@787
  2109
    "decodebin2",
renatofilho@787
  2110
    "decoder bin newer version", plugin_init, VERSION, GST_LICENSE,
renatofilho@787
  2111
    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)