gst-gmyth/decodebin2/gstdecodebin2.c
author melunko
Tue Sep 18 14:09:39 2007 +0100 (2007-09-18)
branchtrunk
changeset 850 b457f7ba9b15
parent 787 e42706ada231
permissions -rw-r--r--
[svn r856] debian/changelog updated
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@792
   453
#if 0
renatofilho@787
   454
  rank = gst_plugin_feature_get_rank (feature);
renatofilho@787
   455
  if (rank < GST_RANK_MARGINAL)
renatofilho@787
   456
    return FALSE;
renatofilho@792
   457
#endif
renatofilho@787
   458
renatofilho@787
   459
  return TRUE;
renatofilho@787
   460
}
renatofilho@787
   461
renatofilho@787
   462
/* function used to sort element features */
renatofilho@787
   463
static gint
renatofilho@787
   464
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
renatofilho@787
   465
{
renatofilho@787
   466
  gint diff;
renatofilho@787
   467
  const gchar *rname1, *rname2;
renatofilho@787
   468
renatofilho@787
   469
  diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
renatofilho@787
   470
  if (diff != 0)
renatofilho@787
   471
    return diff;
renatofilho@787
   472
renatofilho@787
   473
  rname1 = gst_plugin_feature_get_name (f1);
renatofilho@787
   474
  rname2 = gst_plugin_feature_get_name (f2);
renatofilho@787
   475
renatofilho@787
   476
  diff = strcmp (rname2, rname1);
renatofilho@787
   477
renatofilho@787
   478
  return diff;
renatofilho@787
   479
}
renatofilho@787
   480
renatofilho@787
   481
static void
renatofilho@787
   482
print_feature (GstPluginFeature * feature)
renatofilho@787
   483
{
renatofilho@787
   484
  const gchar *rname;
renatofilho@787
   485
renatofilho@787
   486
  rname = gst_plugin_feature_get_name (feature);
renatofilho@787
   487
renatofilho@787
   488
  GST_DEBUG ("%s", rname);
renatofilho@787
   489
}
renatofilho@787
   490
renatofilho@787
   491
static void
renatofilho@787
   492
gst_decode_bin_init (GstDecodeBin * decode_bin)
renatofilho@787
   493
{
renatofilho@787
   494
  GList *factories;
renatofilho@787
   495
renatofilho@787
   496
  /* first filter out the interesting element factories */
renatofilho@787
   497
  factories = gst_default_registry_feature_filter (
renatofilho@787
   498
      (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
renatofilho@787
   499
      FALSE, decode_bin);
renatofilho@787
   500
renatofilho@787
   501
  /* sort them according to their ranks */
renatofilho@787
   502
  decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
renatofilho@787
   503
  /* do some debugging */
renatofilho@787
   504
  g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
renatofilho@787
   505
renatofilho@787
   506
renatofilho@787
   507
  /* we create the typefind element only once */
renatofilho@787
   508
  decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
renatofilho@787
   509
  if (!decode_bin->typefind) {
renatofilho@787
   510
    g_warning ("can't find typefind element, decodebin will not work");
renatofilho@787
   511
  } else {
renatofilho@787
   512
    GstPad *pad;
renatofilho@787
   513
    GstPad *gpad;
renatofilho@787
   514
renatofilho@787
   515
    /* add the typefind element */
renatofilho@787
   516
    if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind)) {
renatofilho@787
   517
      g_warning ("Could not add typefind element, decodebin will not work");
renatofilho@787
   518
      gst_object_unref (decode_bin->typefind);
renatofilho@787
   519
      decode_bin->typefind = NULL;
renatofilho@787
   520
    }
renatofilho@787
   521
renatofilho@787
   522
    /* get the sinkpad */
renatofilho@787
   523
    pad = gst_element_get_pad (decode_bin->typefind, "sink");
renatofilho@787
   524
renatofilho@787
   525
    /* ghost the sink pad to ourself */
renatofilho@787
   526
    gpad = gst_ghost_pad_new ("sink", pad);
renatofilho@787
   527
    gst_pad_set_active (gpad, TRUE);
renatofilho@787
   528
    gst_element_add_pad (GST_ELEMENT (decode_bin), gpad);
renatofilho@787
   529
renatofilho@787
   530
    gst_object_unref (pad);
renatofilho@787
   531
renatofilho@787
   532
    /* connect a signal to find out when the typefind element found
renatofilho@787
   533
     * a type */
renatofilho@787
   534
    g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
renatofilho@787
   535
        G_CALLBACK (type_found), decode_bin);
renatofilho@787
   536
  }
renatofilho@787
   537
renatofilho@787
   538
  decode_bin->lock = g_mutex_new ();
renatofilho@787
   539
  decode_bin->activegroup = NULL;
renatofilho@787
   540
  decode_bin->groups = NULL;
renatofilho@787
   541
renatofilho@787
   542
  decode_bin->caps =
renatofilho@787
   543
      gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray;"
renatofilho@787
   544
      "audio/x-raw-int;audio/x-raw-float;" "text/plain;text/x-pango-markup");
renatofilho@787
   545
renatofilho@787
   546
  add_fakesink (decode_bin);
renatofilho@787
   547
renatofilho@787
   548
  /* FILLME */
renatofilho@787
   549
}
renatofilho@787
   550
renatofilho@787
   551
static void
renatofilho@787
   552
gst_decode_bin_dispose (GObject * object)
renatofilho@787
   553
{
renatofilho@787
   554
  GstDecodeBin *decode_bin;
renatofilho@787
   555
  GList *tmp;
renatofilho@787
   556
renatofilho@787
   557
  decode_bin = GST_DECODE_BIN (object);
renatofilho@787
   558
renatofilho@787
   559
  if (decode_bin->factories)
renatofilho@787
   560
    gst_plugin_feature_list_free (decode_bin->factories);
renatofilho@787
   561
  decode_bin->factories = NULL;
renatofilho@787
   562
renatofilho@787
   563
  if (decode_bin->activegroup) {
renatofilho@787
   564
    gst_decode_group_free (decode_bin->activegroup);
renatofilho@787
   565
    decode_bin->activegroup = NULL;
renatofilho@787
   566
  }
renatofilho@787
   567
renatofilho@787
   568
  /* remove groups */
renatofilho@787
   569
  for (tmp = decode_bin->groups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   570
    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
renatofilho@787
   571
renatofilho@787
   572
    gst_decode_group_free (group);
renatofilho@787
   573
  }
renatofilho@787
   574
  g_list_free (decode_bin->groups);
renatofilho@787
   575
  decode_bin->groups = NULL;
renatofilho@787
   576
renatofilho@787
   577
  for (tmp = decode_bin->oldgroups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   578
    GstDecodeGroup *group = (GstDecodeGroup *) tmp->data;
renatofilho@787
   579
renatofilho@787
   580
    gst_decode_group_free (group);
renatofilho@787
   581
  }
renatofilho@787
   582
  g_list_free (decode_bin->oldgroups);
renatofilho@787
   583
  decode_bin->oldgroups = NULL;
renatofilho@787
   584
renatofilho@787
   585
  if (decode_bin->caps)
renatofilho@787
   586
    gst_caps_unref (decode_bin->caps);
renatofilho@787
   587
  decode_bin->caps = NULL;
renatofilho@787
   588
  remove_fakesink (decode_bin);
renatofilho@787
   589
renatofilho@787
   590
  G_OBJECT_CLASS (parent_class)->dispose (object);
renatofilho@787
   591
}
renatofilho@787
   592
renatofilho@787
   593
static void
renatofilho@787
   594
gst_decode_bin_finalize (GObject * object)
renatofilho@787
   595
{
renatofilho@787
   596
  GstDecodeBin *decode_bin;
renatofilho@787
   597
renatofilho@787
   598
  decode_bin = GST_DECODE_BIN (object);
renatofilho@787
   599
renatofilho@787
   600
  if (decode_bin->lock) {
renatofilho@787
   601
    g_mutex_free (decode_bin->lock);
renatofilho@787
   602
    decode_bin->lock = NULL;
renatofilho@787
   603
  }
renatofilho@787
   604
renatofilho@787
   605
  G_OBJECT_CLASS (parent_class)->finalize (object);
renatofilho@787
   606
}
renatofilho@787
   607
renatofilho@787
   608
static void
renatofilho@787
   609
gst_decode_bin_set_property (GObject * object, guint prop_id,
renatofilho@787
   610
    const GValue * value, GParamSpec * pspec)
renatofilho@787
   611
{
renatofilho@787
   612
  GstDecodeBin *dbin;
renatofilho@787
   613
renatofilho@787
   614
  dbin = GST_DECODE_BIN (object);
renatofilho@787
   615
renatofilho@787
   616
  switch (prop_id) {
renatofilho@787
   617
    case PROP_CAPS:
renatofilho@787
   618
      gst_decode_bin_set_caps (dbin, (GstCaps *) g_value_dup_boxed (value));
renatofilho@787
   619
      break;
renatofilho@787
   620
    default:
renatofilho@787
   621
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
renatofilho@787
   622
      break;
renatofilho@787
   623
  }
renatofilho@787
   624
}
renatofilho@787
   625
renatofilho@787
   626
static void
renatofilho@787
   627
gst_decode_bin_get_property (GObject * object, guint prop_id,
renatofilho@787
   628
    GValue * value, GParamSpec * pspec)
renatofilho@787
   629
{
renatofilho@787
   630
  GstDecodeBin *dbin;
renatofilho@787
   631
renatofilho@787
   632
  dbin = GST_DECODE_BIN (object);
renatofilho@787
   633
  switch (prop_id) {
renatofilho@787
   634
    case PROP_CAPS:{
renatofilho@787
   635
      g_value_take_boxed (value, gst_decode_bin_get_caps (dbin));
renatofilho@787
   636
      break;
renatofilho@787
   637
    }
renatofilho@787
   638
    default:
renatofilho@787
   639
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
renatofilho@787
   640
      break;
renatofilho@787
   641
  }
renatofilho@787
   642
renatofilho@787
   643
}
renatofilho@787
   644
renatofilho@787
   645
/* _set_caps
renatofilho@787
   646
 * Changes the caps on which decodebin will stop decoding.
renatofilho@787
   647
 * Will unref the previously set one. The refcount of the given caps will be
renatofilho@787
   648
 * taken.
renatofilho@787
   649
 * @caps can be NULL.
renatofilho@787
   650
 *
renatofilho@787
   651
 * MT-safe
renatofilho@787
   652
 */
renatofilho@787
   653
renatofilho@787
   654
static void
renatofilho@787
   655
gst_decode_bin_set_caps (GstDecodeBin * dbin, GstCaps * caps)
renatofilho@787
   656
{
renatofilho@787
   657
  GST_DEBUG_OBJECT (dbin, "Setting new caps: %" GST_PTR_FORMAT, caps);
renatofilho@787
   658
renatofilho@787
   659
  DECODE_BIN_LOCK (dbin);
renatofilho@787
   660
  if (dbin->caps)
renatofilho@787
   661
    gst_caps_unref (dbin->caps);
renatofilho@787
   662
  dbin->caps = caps;
renatofilho@787
   663
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   664
}
renatofilho@787
   665
renatofilho@787
   666
/* _get_caps
renatofilho@787
   667
 * Returns the currently configured caps on which decodebin will stop decoding.
renatofilho@787
   668
 * The returned caps (if not NULL), will have its refcount incremented.
renatofilho@787
   669
 *
renatofilho@787
   670
 * MT-safe
renatofilho@787
   671
 */
renatofilho@787
   672
renatofilho@787
   673
static GstCaps *
renatofilho@787
   674
gst_decode_bin_get_caps (GstDecodeBin * dbin)
renatofilho@787
   675
{
renatofilho@787
   676
  GstCaps *caps;
renatofilho@787
   677
renatofilho@787
   678
  GST_DEBUG_OBJECT (dbin, "Getting currently set caps");
renatofilho@787
   679
renatofilho@787
   680
  DECODE_BIN_LOCK (dbin);
renatofilho@787
   681
  caps = dbin->caps;
renatofilho@787
   682
  if (caps)
renatofilho@787
   683
    gst_caps_ref (caps);
renatofilho@787
   684
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   685
renatofilho@787
   686
  return caps;
renatofilho@787
   687
}
renatofilho@787
   688
renatofilho@787
   689
/*****
renatofilho@787
   690
 * Default autoplug signal handlers
renatofilho@787
   691
 *****/
renatofilho@787
   692
renatofilho@787
   693
static gboolean
renatofilho@787
   694
gst_decode_bin_autoplug_continue (GstElement * element, GstCaps * caps)
renatofilho@787
   695
{
renatofilho@787
   696
  return TRUE;
renatofilho@787
   697
}
renatofilho@787
   698
renatofilho@787
   699
static gboolean
renatofilho@787
   700
gst_decode_bin_autoplug_sort (GstElement * element, GstCaps * caps,
renatofilho@787
   701
    GList ** list)
renatofilho@787
   702
{
renatofilho@787
   703
  return TRUE;
renatofilho@787
   704
}
renatofilho@787
   705
renatofilho@787
   706
renatofilho@787
   707
renatofilho@787
   708
/********
renatofilho@787
   709
 * Discovery methods
renatofilho@787
   710
 *****/
renatofilho@787
   711
renatofilho@787
   712
static gboolean are_raw_caps (GstDecodeBin * dbin, GstCaps * caps);
renatofilho@787
   713
static gboolean is_demuxer_element (GstElement * srcelement);
renatofilho@787
   714
static GList *find_compatibles (GstDecodeBin * decode_bin,
renatofilho@787
   715
    const GstCaps * caps);
renatofilho@787
   716
renatofilho@787
   717
static gboolean connect_pad (GstDecodeBin * dbin, GstElement * src,
renatofilho@787
   718
    GstPad * pad, GList * factories, GstDecodeGroup * group);
renatofilho@787
   719
static gboolean connect_element (GstDecodeBin * dbin, GstElement * element,
renatofilho@787
   720
    GstDecodeGroup * group);
renatofilho@787
   721
static void expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   722
    GstDecodeGroup * group);
renatofilho@787
   723
renatofilho@787
   724
static void pad_added_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
   725
    GstDecodeGroup * group);
renatofilho@787
   726
static void pad_removed_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
   727
    GstDecodeGroup * group);
renatofilho@787
   728
static void no_more_pads_group_cb (GstElement * element,
renatofilho@787
   729
    GstDecodeGroup * group);
renatofilho@787
   730
static void pad_added_cb (GstElement * element, GstPad * pad,
renatofilho@787
   731
    GstDecodeBin * dbin);
renatofilho@787
   732
static void pad_removed_cb (GstElement * element, GstPad * pad,
renatofilho@787
   733
    GstDecodeBin * dbin);
renatofilho@787
   734
static void no_more_pads_cb (GstElement * element, GstDecodeBin * dbin);
renatofilho@787
   735
renatofilho@787
   736
static GstDecodeGroup *get_current_group (GstDecodeBin * dbin);
renatofilho@787
   737
renatofilho@787
   738
static void
renatofilho@787
   739
analyze_new_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   740
    GstCaps * caps, GstDecodeGroup * group)
renatofilho@787
   741
{
renatofilho@787
   742
  gboolean apcontinue = TRUE;
renatofilho@787
   743
  GList *factories = NULL;
renatofilho@787
   744
  gboolean apsort = TRUE;
renatofilho@787
   745
renatofilho@787
   746
  GST_DEBUG_OBJECT (dbin, "Pad %s:%s caps:%" GST_PTR_FORMAT,
renatofilho@787
   747
      GST_DEBUG_PAD_NAME (pad), caps);
renatofilho@787
   748
renatofilho@787
   749
  if ((caps == NULL) || gst_caps_is_empty (caps))
renatofilho@787
   750
    goto unknown_type;
renatofilho@787
   751
renatofilho@787
   752
  if (gst_caps_is_any (caps))
renatofilho@787
   753
    goto any_caps;
renatofilho@787
   754
renatofilho@787
   755
  /* 1. Emit 'autoplug-continue' */
renatofilho@787
   756
  g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   757
      gst_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, caps, &apcontinue);
renatofilho@787
   758
renatofilho@787
   759
  /* 1.a if autoplug-continue is FALSE or caps is a raw format, goto pad_is_final */
renatofilho@787
   760
  if ((!apcontinue) || are_raw_caps (dbin, caps))
renatofilho@787
   761
    goto expose_pad;
renatofilho@787
   762
renatofilho@787
   763
  /* 1.b else if there's no compatible factory or 'autoplug-sort' returned FALSE, goto pad_not_used */
renatofilho@787
   764
  if ((factories = find_compatibles (dbin, caps))) {
renatofilho@787
   765
    /* emit autoplug-sort */
renatofilho@787
   766
    g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   767
        gst_decode_bin_signals[SIGNAL_AUTOPLUG_SORT],
renatofilho@787
   768
        0, caps, &factories, &apsort);
renatofilho@787
   769
    if (!apsort) {
renatofilho@787
   770
      g_list_free (factories);
renatofilho@787
   771
      /* User doesn't want that pad */
renatofilho@787
   772
      goto pad_not_wanted;
renatofilho@787
   773
    }
renatofilho@787
   774
  } else {
renatofilho@787
   775
    /* no compatible factories */
renatofilho@787
   776
    goto unknown_type;
renatofilho@787
   777
  }
renatofilho@787
   778
renatofilho@787
   779
  /* 1.c else goto pad_is_valid */
renatofilho@787
   780
  GST_LOG_OBJECT (pad, "Let's continue discovery on this pad");
renatofilho@787
   781
renatofilho@787
   782
  connect_pad (dbin, src, pad, factories, group);
renatofilho@787
   783
  g_list_free (factories);
renatofilho@787
   784
renatofilho@787
   785
  return;
renatofilho@787
   786
renatofilho@787
   787
expose_pad:
renatofilho@787
   788
  {
renatofilho@787
   789
    GST_LOG_OBJECT (dbin, "Pad is final. autoplug-continue:%d", apcontinue);
renatofilho@787
   790
    expose_pad (dbin, src, pad, group);
renatofilho@787
   791
    return;
renatofilho@787
   792
  }
renatofilho@787
   793
renatofilho@787
   794
pad_not_wanted:
renatofilho@787
   795
  {
renatofilho@787
   796
    GST_LOG_OBJECT (pad, "User doesn't want this pad, stopping discovery");
renatofilho@787
   797
    return;
renatofilho@787
   798
  }
renatofilho@787
   799
renatofilho@787
   800
unknown_type:
renatofilho@787
   801
  {
renatofilho@787
   802
    GST_LOG_OBJECT (pad, "Unknown type, firing signal");
renatofilho@787
   803
    g_signal_emit (G_OBJECT (dbin),
renatofilho@787
   804
        gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
renatofilho@787
   805
renatofilho@787
   806
    /* Check if there are no pending groups, if so, remove fakesink */
renatofilho@787
   807
    if (dbin->groups == NULL)
renatofilho@787
   808
      remove_fakesink (dbin);
renatofilho@787
   809
renatofilho@787
   810
    return;
renatofilho@787
   811
  }
renatofilho@787
   812
renatofilho@787
   813
any_caps:
renatofilho@787
   814
  {
renatofilho@787
   815
    GST_WARNING_OBJECT (pad,
renatofilho@787
   816
        "pad has ANY caps, not able to autoplug to anything");
renatofilho@787
   817
    /* FIXME : connect to caps notification */
renatofilho@787
   818
    return;
renatofilho@787
   819
  }
renatofilho@787
   820
}
renatofilho@787
   821
renatofilho@787
   822
renatofilho@787
   823
/* connect_pad:
renatofilho@787
   824
 *
renatofilho@787
   825
 * Try to connect the given pad to an element created from one of the factories,
renatofilho@787
   826
 * and recursively.
renatofilho@787
   827
 *
renatofilho@787
   828
 * Returns TRUE if an element was properly created and linked
renatofilho@787
   829
 */
renatofilho@787
   830
renatofilho@787
   831
static gboolean
renatofilho@787
   832
connect_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
   833
    GList * factories, GstDecodeGroup * group)
renatofilho@787
   834
{
renatofilho@787
   835
  gboolean res = FALSE;
renatofilho@787
   836
  GList *tmp;
renatofilho@787
   837
renatofilho@787
   838
  g_return_val_if_fail (factories != NULL, FALSE);
renatofilho@787
   839
  GST_DEBUG_OBJECT (dbin, "pad %s:%s , group:%p",
renatofilho@787
   840
      GST_DEBUG_PAD_NAME (pad), group);
renatofilho@787
   841
renatofilho@787
   842
  /* 1. is element demuxer or parser */
renatofilho@787
   843
  if (is_demuxer_element (src)) {
renatofilho@787
   844
    GstPad *mqpad;
renatofilho@787
   845
renatofilho@787
   846
    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
renatofilho@787
   847
renatofilho@787
   848
    if (!group)
renatofilho@787
   849
      if (!(group = get_current_group (dbin))) {
renatofilho@787
   850
        group = gst_decode_group_new (dbin);
renatofilho@787
   851
        DECODE_BIN_LOCK (dbin);
renatofilho@787
   852
        dbin->groups = g_list_append (dbin->groups, group);
renatofilho@787
   853
        DECODE_BIN_UNLOCK (dbin);
renatofilho@787
   854
      }
renatofilho@787
   855
renatofilho@787
   856
    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
renatofilho@787
   857
      goto beach;
renatofilho@787
   858
    pad = mqpad;
renatofilho@787
   859
  }
renatofilho@787
   860
renatofilho@787
   861
  /* 2. Try to create an element and link to it */
renatofilho@787
   862
  for (tmp = factories; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
   863
    GstElementFactory *factory = (GstElementFactory *) tmp->data;
renatofilho@787
   864
    GstElement *element;
renatofilho@787
   865
    GstPad *sinkpad;
renatofilho@787
   866
renatofilho@787
   867
    /* 2.1. Try to create an element */
renatofilho@787
   868
    if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
renatofilho@787
   869
      GST_WARNING_OBJECT (dbin, "Could not create an element from %s",
renatofilho@787
   870
          gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
renatofilho@787
   871
      continue;
renatofilho@787
   872
    }
renatofilho@787
   873
renatofilho@787
   874
    /* 2.3. Find its sink pad */
renatofilho@787
   875
    if (!(sinkpad = find_sink_pad (element))) {
renatofilho@787
   876
      GST_WARNING_OBJECT (dbin, "Element %s doesn't have a sink pad",
renatofilho@787
   877
          GST_ELEMENT_NAME (element));
renatofilho@787
   878
      gst_object_unref (element);
renatofilho@787
   879
      continue;
renatofilho@787
   880
    }
renatofilho@787
   881
renatofilho@787
   882
    /* 2.4 add it ... */
renatofilho@787
   883
    if (!(gst_bin_add (GST_BIN (dbin), element))) {
renatofilho@787
   884
      GST_WARNING_OBJECT (dbin, "Couldn't add %s to the bin",
renatofilho@787
   885
          GST_ELEMENT_NAME (element));
renatofilho@787
   886
      gst_object_unref (sinkpad);
renatofilho@787
   887
      gst_object_unref (element);
renatofilho@787
   888
      continue;
renatofilho@787
   889
    }
renatofilho@787
   890
renatofilho@787
   891
    /* ... activate it ... */
renatofilho@787
   892
    if ((gst_element_set_state (element,
renatofilho@787
   893
                GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
renatofilho@787
   894
      GST_WARNING_OBJECT (dbin, "Couldn't set %s to READY",
renatofilho@787
   895
          GST_ELEMENT_NAME (element));
renatofilho@787
   896
      gst_object_unref (sinkpad);
renatofilho@787
   897
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   898
      continue;
renatofilho@787
   899
    }
renatofilho@787
   900
renatofilho@787
   901
    /* 2.5 ...and try to link */
renatofilho@787
   902
    if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
renatofilho@787
   903
      GST_WARNING_OBJECT (dbin, "Link failed on pad %s:%s",
renatofilho@787
   904
          GST_DEBUG_PAD_NAME (sinkpad));
renatofilho@787
   905
      gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
   906
      gst_object_unref (sinkpad);
renatofilho@787
   907
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   908
      continue;
renatofilho@787
   909
    }
renatofilho@787
   910
renatofilho@787
   911
    GST_LOG_OBJECT (dbin, "linked on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
renatofilho@787
   912
renatofilho@787
   913
    /* link this element further */
renatofilho@787
   914
    connect_element (dbin, element, group);
renatofilho@787
   915
renatofilho@787
   916
    /* Bring the element to the state of the parent */
renatofilho@787
   917
    if ((gst_element_set_state (element,
renatofilho@787
   918
                GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
renatofilho@787
   919
      GST_WARNING_OBJECT (dbin, "Couldn't set %s to PAUSED",
renatofilho@787
   920
          GST_ELEMENT_NAME (element));
renatofilho@787
   921
      gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
   922
      gst_object_unref (sinkpad);
renatofilho@787
   923
      gst_bin_remove (GST_BIN (dbin), element);
renatofilho@787
   924
      continue;
renatofilho@787
   925
    }
renatofilho@787
   926
renatofilho@787
   927
    res = TRUE;
renatofilho@787
   928
    break;
renatofilho@787
   929
  }
renatofilho@787
   930
renatofilho@787
   931
beach:
renatofilho@787
   932
  return res;
renatofilho@787
   933
}
renatofilho@787
   934
renatofilho@787
   935
static gboolean
renatofilho@787
   936
connect_element (GstDecodeBin * dbin, GstElement * element,
renatofilho@787
   937
    GstDecodeGroup * group)
renatofilho@787
   938
{
renatofilho@787
   939
  GList *pads;
renatofilho@787
   940
  gboolean res = TRUE;
renatofilho@787
   941
  gboolean dynamic = FALSE;
renatofilho@787
   942
  GList *to_connect = NULL;
renatofilho@787
   943
renatofilho@787
   944
  GST_DEBUG_OBJECT (dbin, "Attempting to connect element %s [group:%p] further",
renatofilho@787
   945
      GST_ELEMENT_NAME (element), group);
renatofilho@787
   946
renatofilho@787
   947
  /* 1. Loop over pad templates, grabbing existing pads along the way */
renatofilho@787
   948
  for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
renatofilho@787
   949
      pads = g_list_next (pads)) {
renatofilho@787
   950
    GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
renatofilho@787
   951
    const gchar *templ_name;
renatofilho@787
   952
renatofilho@787
   953
    /* we are only interested in source pads */
renatofilho@787
   954
    if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
renatofilho@787
   955
      continue;
renatofilho@787
   956
renatofilho@787
   957
    templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
renatofilho@787
   958
    GST_DEBUG_OBJECT (dbin, "got a source pad template %s", templ_name);
renatofilho@787
   959
renatofilho@787
   960
    /* figure out what kind of pad this is */
renatofilho@787
   961
    switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
renatofilho@787
   962
      case GST_PAD_ALWAYS:
renatofilho@787
   963
      {
renatofilho@787
   964
        /* get the pad that we need to autoplug */
renatofilho@787
   965
        GstPad *pad = gst_element_get_pad (element, templ_name);
renatofilho@787
   966
renatofilho@787
   967
        if (pad) {
renatofilho@787
   968
          GST_DEBUG_OBJECT (dbin, "got the pad for always template %s",
renatofilho@787
   969
              templ_name);
renatofilho@787
   970
          /* here is the pad, we need to autoplug it */
renatofilho@787
   971
          to_connect = g_list_prepend (to_connect, pad);
renatofilho@787
   972
        } else {
renatofilho@787
   973
          /* strange, pad is marked as always but it's not
renatofilho@787
   974
           * there. Fix the element */
renatofilho@787
   975
          GST_WARNING_OBJECT (dbin,
renatofilho@787
   976
              "could not get the pad for always template %s", templ_name);
renatofilho@787
   977
        }
renatofilho@787
   978
        break;
renatofilho@787
   979
      }
renatofilho@787
   980
      case GST_PAD_SOMETIMES:
renatofilho@787
   981
      {
renatofilho@787
   982
        /* try to get the pad to see if it is already created or
renatofilho@787
   983
         * not */
renatofilho@787
   984
        GstPad *pad = gst_element_get_pad (element, templ_name);
renatofilho@787
   985
renatofilho@787
   986
        if (pad) {
renatofilho@787
   987
          GST_DEBUG_OBJECT (dbin, "got the pad for sometimes template %s",
renatofilho@787
   988
              templ_name);
renatofilho@787
   989
          /* the pad is created, we need to autoplug it */
renatofilho@787
   990
          to_connect = g_list_prepend (to_connect, pad);
renatofilho@787
   991
        } else {
renatofilho@787
   992
          GST_DEBUG_OBJECT (dbin,
renatofilho@787
   993
              "did not get the sometimes pad of template %s", templ_name);
renatofilho@787
   994
          /* we have an element that will create dynamic pads */
renatofilho@787
   995
          dynamic = TRUE;
renatofilho@787
   996
        }
renatofilho@787
   997
        break;
renatofilho@787
   998
      }
renatofilho@787
   999
      case GST_PAD_REQUEST:
renatofilho@787
  1000
        /* ignore request pads */
renatofilho@787
  1001
        GST_DEBUG_OBJECT (dbin, "ignoring request padtemplate %s", templ_name);
renatofilho@787
  1002
        break;
renatofilho@787
  1003
    }
renatofilho@787
  1004
  }
renatofilho@787
  1005
renatofilho@787
  1006
  /* 2. if there are more potential pads, connect to relevent signals */
renatofilho@787
  1007
  if (dynamic) {
renatofilho@787
  1008
    if (group) {
renatofilho@787
  1009
      GST_LOG ("Adding signals to element %s in group %p",
renatofilho@787
  1010
          GST_ELEMENT_NAME (element), group);
renatofilho@787
  1011
      GROUP_MUTEX_LOCK (group);
renatofilho@787
  1012
      group->nbdynamic++;
renatofilho@787
  1013
      GST_LOG ("Group %p has now %d dynamic elements", group, group->nbdynamic);
renatofilho@787
  1014
      GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1015
      g_signal_connect (G_OBJECT (element), "pad-added",
renatofilho@787
  1016
          G_CALLBACK (pad_added_group_cb), group);
renatofilho@787
  1017
      g_signal_connect (G_OBJECT (element), "pad-removed",
renatofilho@787
  1018
          G_CALLBACK (pad_removed_group_cb), group);
renatofilho@787
  1019
      g_signal_connect (G_OBJECT (element), "no-more-pads",
renatofilho@787
  1020
          G_CALLBACK (no_more_pads_group_cb), group);
renatofilho@787
  1021
    } else {
renatofilho@787
  1022
      /* This is a non-grouped element, the handlers are different */
renatofilho@787
  1023
      g_signal_connect (G_OBJECT (element), "pad-added",
renatofilho@787
  1024
          G_CALLBACK (pad_added_cb), dbin);
renatofilho@787
  1025
      g_signal_connect (G_OBJECT (element), "pad-removed",
renatofilho@787
  1026
          G_CALLBACK (pad_removed_cb), dbin);
renatofilho@787
  1027
      g_signal_connect (G_OBJECT (element), "no-more-pads",
renatofilho@787
  1028
          G_CALLBACK (no_more_pads_cb), dbin);
renatofilho@787
  1029
    }
renatofilho@787
  1030
  }
renatofilho@787
  1031
renatofilho@787
  1032
  /* 3. for every available pad, connect it */
renatofilho@787
  1033
  for (pads = to_connect; pads; pads = g_list_next (pads)) {
renatofilho@787
  1034
    GstPad *pad = GST_PAD_CAST (pads->data);
renatofilho@787
  1035
    GstCaps *caps;
renatofilho@787
  1036
renatofilho@787
  1037
    caps = gst_pad_get_caps (pad);
renatofilho@787
  1038
    analyze_new_pad (dbin, element, pad, caps, group);
renatofilho@787
  1039
    if (caps)
renatofilho@787
  1040
      gst_caps_unref (caps);
renatofilho@787
  1041
renatofilho@787
  1042
    gst_object_unref (pad);
renatofilho@787
  1043
  }
renatofilho@787
  1044
  g_list_free (to_connect);
renatofilho@787
  1045
renatofilho@787
  1046
  return res;
renatofilho@787
  1047
}
renatofilho@787
  1048
renatofilho@787
  1049
/* expose_pad:
renatofilho@787
  1050
 *
renatofilho@787
  1051
 * Expose the given pad on the group as a decoded pad.
renatofilho@787
  1052
 * If group is NULL, a GstDecodeGroup will be created and setup properly.
renatofilho@787
  1053
 */
renatofilho@787
  1054
static void
renatofilho@787
  1055
expose_pad (GstDecodeBin * dbin, GstElement * src, GstPad * pad,
renatofilho@787
  1056
    GstDecodeGroup * group)
renatofilho@787
  1057
{
renatofilho@787
  1058
  gboolean newgroup = FALSE;
renatofilho@787
  1059
  gboolean isdemux;
renatofilho@787
  1060
renatofilho@787
  1061
  GST_DEBUG_OBJECT (dbin, "pad %s:%s, group:%p",
renatofilho@787
  1062
      GST_DEBUG_PAD_NAME (pad), group);
renatofilho@787
  1063
renatofilho@787
  1064
  if (!group)
renatofilho@787
  1065
    if (!(group = get_current_group (dbin))) {
renatofilho@787
  1066
      group = gst_decode_group_new (dbin);
renatofilho@787
  1067
      DECODE_BIN_LOCK (dbin);
renatofilho@787
  1068
      dbin->groups = g_list_append (dbin->groups, group);
renatofilho@787
  1069
      DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1070
      newgroup = TRUE;
renatofilho@787
  1071
    }
renatofilho@787
  1072
renatofilho@787
  1073
  isdemux = is_demuxer_element (src);
renatofilho@787
  1074
renatofilho@787
  1075
  if (isdemux || newgroup) {
renatofilho@787
  1076
    GstPad *mqpad;
renatofilho@787
  1077
renatofilho@787
  1078
    GST_LOG_OBJECT (src, "is a demuxer, connecting the pad through multiqueue");
renatofilho@787
  1079
renatofilho@787
  1080
    if (!(mqpad = gst_decode_group_control_demuxer_pad (group, pad)))
renatofilho@787
  1081
      goto beach;
renatofilho@787
  1082
    pad = mqpad;
renatofilho@787
  1083
  }
renatofilho@787
  1084
renatofilho@787
  1085
  gst_decode_group_control_source_pad (group, pad);
renatofilho@787
  1086
renatofilho@787
  1087
  if (newgroup && !isdemux) {
renatofilho@787
  1088
    /* If we have discovered a raw pad and it doesn't belong to any group,
renatofilho@787
  1089
     * that means there wasn't any demuxer. In that case, we consider the
renatofilho@787
  1090
     * group as being complete. */
renatofilho@787
  1091
    gst_decode_group_set_complete (group);
renatofilho@787
  1092
  }
renatofilho@787
  1093
beach:
renatofilho@787
  1094
  return;
renatofilho@787
  1095
}
renatofilho@787
  1096
renatofilho@787
  1097
static void
renatofilho@787
  1098
type_found (GstElement * typefind, guint probability,
renatofilho@787
  1099
    GstCaps * caps, GstDecodeBin * decode_bin)
renatofilho@787
  1100
{
renatofilho@787
  1101
  GstPad *pad;
renatofilho@787
  1102
renatofilho@787
  1103
  GST_STATE_LOCK (decode_bin);
renatofilho@787
  1104
renatofilho@787
  1105
  GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
renatofilho@787
  1106
renatofilho@787
  1107
  pad = gst_element_get_pad (typefind, "src");
renatofilho@787
  1108
renatofilho@787
  1109
  analyze_new_pad (decode_bin, typefind, pad, caps, NULL);
renatofilho@787
  1110
renatofilho@787
  1111
  gst_object_unref (pad);
renatofilho@787
  1112
renatofilho@787
  1113
  GST_STATE_UNLOCK (decode_bin);
renatofilho@787
  1114
  return;
renatofilho@787
  1115
}
renatofilho@787
  1116
renatofilho@787
  1117
static void
renatofilho@787
  1118
pad_added_group_cb (GstElement * element, GstPad * pad, GstDecodeGroup * group)
renatofilho@787
  1119
{
renatofilho@787
  1120
  GstCaps *caps;
renatofilho@787
  1121
  gboolean expose = FALSE;
renatofilho@787
  1122
renatofilho@787
  1123
  GST_LOG_OBJECT (pad, "pad added, group:%p", group);
renatofilho@787
  1124
renatofilho@787
  1125
  caps = gst_pad_get_caps (pad);
renatofilho@787
  1126
  analyze_new_pad (group->dbin, element, pad, caps, group);
renatofilho@787
  1127
  if (caps)
renatofilho@787
  1128
    gst_caps_unref (caps);
renatofilho@787
  1129
renatofilho@787
  1130
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1131
  group->nbdynamic--;
renatofilho@787
  1132
  GST_LOG ("Group %p has now %d dynamic objects", group, group->nbdynamic);
renatofilho@787
  1133
  if (group->nbdynamic == 0)
renatofilho@787
  1134
    expose = TRUE;
renatofilho@787
  1135
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1136
  if (expose) {
renatofilho@787
  1137
    GST_LOG
renatofilho@787
  1138
        ("That was the last dynamic object, now attempting to expose the group");
renatofilho@787
  1139
    DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1140
    gst_decode_group_expose (group);
renatofilho@787
  1141
    DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1142
  }
renatofilho@787
  1143
}
renatofilho@787
  1144
renatofilho@787
  1145
static void
renatofilho@787
  1146
pad_removed_group_cb (GstElement * element, GstPad * pad,
renatofilho@787
  1147
    GstDecodeGroup * group)
renatofilho@787
  1148
{
renatofilho@787
  1149
  GST_LOG_OBJECT (pad, "pad removed, group:%p", group);
renatofilho@787
  1150
renatofilho@787
  1151
  /* In fact, we don't have to do anything here, the active group will be
renatofilho@787
  1152
   * removed when the group's multiqueue is drained */
renatofilho@787
  1153
}
renatofilho@787
  1154
renatofilho@787
  1155
static void
renatofilho@787
  1156
no_more_pads_group_cb (GstElement * element, GstDecodeGroup * group)
renatofilho@787
  1157
{
renatofilho@787
  1158
  GST_LOG_OBJECT (element, "no more pads, setting group %p to complete", group);
renatofilho@787
  1159
renatofilho@787
  1160
  /* FIXME : FILLME */
renatofilho@787
  1161
  gst_decode_group_set_complete (group);
renatofilho@787
  1162
}
renatofilho@787
  1163
renatofilho@787
  1164
static void
renatofilho@787
  1165
pad_added_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
renatofilho@787
  1166
{
renatofilho@787
  1167
  GstCaps *caps;
renatofilho@787
  1168
renatofilho@787
  1169
  GST_LOG_OBJECT (pad, "Pad added to non-grouped element");
renatofilho@787
  1170
renatofilho@787
  1171
  caps = gst_pad_get_caps (pad);
renatofilho@787
  1172
  analyze_new_pad (dbin, element, pad, caps, NULL);
renatofilho@787
  1173
  if (caps)
renatofilho@787
  1174
    gst_caps_unref (caps);
renatofilho@787
  1175
}
renatofilho@787
  1176
renatofilho@787
  1177
static void
renatofilho@787
  1178
pad_removed_cb (GstElement * element, GstPad * pad, GstDecodeBin * dbin)
renatofilho@787
  1179
{
renatofilho@787
  1180
  GST_LOG_OBJECT (pad, "Pad removed from non-grouped element");
renatofilho@787
  1181
}
renatofilho@787
  1182
renatofilho@787
  1183
static void
renatofilho@787
  1184
no_more_pads_cb (GstElement * element, GstDecodeBin * dbin)
renatofilho@787
  1185
{
renatofilho@787
  1186
  GstDecodeGroup *group;
renatofilho@787
  1187
renatofilho@787
  1188
  GST_LOG_OBJECT (element, "No more pads, setting current group to complete");
renatofilho@787
  1189
renatofilho@787
  1190
  /* Find the non-complete group, there should only be one */
renatofilho@787
  1191
  if (!(group = get_current_group (dbin)))
renatofilho@787
  1192
    goto no_group;
renatofilho@787
  1193
renatofilho@787
  1194
  gst_decode_group_set_complete (group);
renatofilho@787
  1195
  return;
renatofilho@787
  1196
renatofilho@787
  1197
no_group:
renatofilho@787
  1198
  {
renatofilho@787
  1199
    GST_WARNING_OBJECT (dbin, "We couldn't find a non-completed group !!");
renatofilho@787
  1200
    return;
renatofilho@787
  1201
  }
renatofilho@787
  1202
}
renatofilho@787
  1203
renatofilho@787
  1204
/* this function runs through the element factories and returns a list
renatofilho@787
  1205
 * of all elements that are able to sink the given caps 
renatofilho@787
  1206
 */
renatofilho@787
  1207
static GList *
renatofilho@787
  1208
find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
renatofilho@787
  1209
{
renatofilho@787
  1210
  GList *factories;
renatofilho@787
  1211
  GList *to_try = NULL;
renatofilho@787
  1212
renatofilho@787
  1213
  /* loop over all the factories */
renatofilho@787
  1214
  for (factories = decode_bin->factories; factories;
renatofilho@787
  1215
      factories = g_list_next (factories)) {
renatofilho@787
  1216
    GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
renatofilho@787
  1217
    const GList *templates;
renatofilho@787
  1218
    GList *walk;
renatofilho@787
  1219
renatofilho@787
  1220
    /* get the templates from the element factory */
renatofilho@787
  1221
    templates = gst_element_factory_get_static_pad_templates (factory);
renatofilho@787
  1222
    for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
renatofilho@787
  1223
      GstStaticPadTemplate *templ = walk->data;
renatofilho@787
  1224
renatofilho@787
  1225
      /* we only care about the sink templates */
renatofilho@787
  1226
      if (templ->direction == GST_PAD_SINK) {
renatofilho@787
  1227
        GstCaps *intersect;
renatofilho@787
  1228
        GstCaps *tmpl_caps;
renatofilho@787
  1229
renatofilho@787
  1230
        /* try to intersect the caps with the caps of the template */
renatofilho@787
  1231
        tmpl_caps = gst_static_caps_get (&templ->static_caps);
renatofilho@787
  1232
renatofilho@787
  1233
        intersect = gst_caps_intersect (caps, tmpl_caps);
renatofilho@787
  1234
        gst_caps_unref (tmpl_caps);
renatofilho@787
  1235
renatofilho@787
  1236
        /* check if the intersection is empty */
renatofilho@787
  1237
        if (!gst_caps_is_empty (intersect)) {
renatofilho@787
  1238
          /* non empty intersection, we can use this element */
renatofilho@787
  1239
          to_try = g_list_prepend (to_try, factory);
renatofilho@787
  1240
          gst_caps_unref (intersect);
renatofilho@787
  1241
          break;
renatofilho@787
  1242
        }
renatofilho@787
  1243
        gst_caps_unref (intersect);
renatofilho@787
  1244
      }
renatofilho@787
  1245
    }
renatofilho@787
  1246
  }
renatofilho@787
  1247
  to_try = g_list_reverse (to_try);
renatofilho@787
  1248
renatofilho@787
  1249
  return to_try;
renatofilho@787
  1250
}
renatofilho@787
  1251
renatofilho@787
  1252
/* Decide whether an element is a demuxer based on the 
renatofilho@787
  1253
 * klass and number/type of src pad templates it has */
renatofilho@787
  1254
static gboolean
renatofilho@787
  1255
is_demuxer_element (GstElement * srcelement)
renatofilho@787
  1256
{
renatofilho@787
  1257
  GstElementFactory *srcfactory;
renatofilho@787
  1258
  GstElementClass *elemclass;
renatofilho@787
  1259
  GList *templates, *walk;
renatofilho@787
  1260
  const gchar *klass;
renatofilho@787
  1261
  gint potential_src_pads = 0;
renatofilho@787
  1262
renatofilho@787
  1263
  srcfactory = gst_element_get_factory (srcelement);
renatofilho@787
  1264
  klass = gst_element_factory_get_klass (srcfactory);
renatofilho@787
  1265
renatofilho@787
  1266
  /* Can't be a demuxer unless it has Demux in the klass name */
renatofilho@787
  1267
  if (!strstr (klass, "Demux"))
renatofilho@787
  1268
    return FALSE;
renatofilho@787
  1269
renatofilho@787
  1270
  /* Walk the src pad templates and count how many the element
renatofilho@787
  1271
   * might produce */
renatofilho@787
  1272
  elemclass = GST_ELEMENT_GET_CLASS (srcelement);
renatofilho@787
  1273
renatofilho@787
  1274
  walk = templates = gst_element_class_get_pad_template_list (elemclass);
renatofilho@787
  1275
  while (walk != NULL) {
renatofilho@787
  1276
    GstPadTemplate *templ;
renatofilho@787
  1277
renatofilho@787
  1278
    templ = (GstPadTemplate *) walk->data;
renatofilho@787
  1279
    if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
renatofilho@787
  1280
      switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
renatofilho@787
  1281
        case GST_PAD_ALWAYS:
renatofilho@787
  1282
        case GST_PAD_SOMETIMES:
renatofilho@787
  1283
          if (strstr (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ), "%"))
renatofilho@787
  1284
            potential_src_pads += 2;    /* Might make multiple pads */
renatofilho@787
  1285
          else
renatofilho@787
  1286
            potential_src_pads += 1;
renatofilho@787
  1287
          break;
renatofilho@787
  1288
        case GST_PAD_REQUEST:
renatofilho@787
  1289
          potential_src_pads += 2;
renatofilho@787
  1290
          break;
renatofilho@787
  1291
      }
renatofilho@787
  1292
    }
renatofilho@787
  1293
    walk = g_list_next (walk);
renatofilho@787
  1294
  }
renatofilho@787
  1295
renatofilho@787
  1296
  if (potential_src_pads < 2)
renatofilho@787
  1297
    return FALSE;
renatofilho@787
  1298
renatofilho@787
  1299
  return TRUE;
renatofilho@787
  1300
}
renatofilho@787
  1301
renatofilho@787
  1302
/* Returns TRUE if the caps are raw, or if they are compatible with the caps 
renatofilho@787
  1303
 * specified in the 'caps' property 
renatofilho@787
  1304
 * 
renatofilho@787
  1305
 * The decodebin_lock should be taken !
renatofilho@787
  1306
 */
renatofilho@787
  1307
static gboolean
renatofilho@787
  1308
are_raw_caps (GstDecodeBin * dbin, GstCaps * caps)
renatofilho@787
  1309
{
renatofilho@787
  1310
  GstCaps *intersection;
renatofilho@787
  1311
  gboolean res;
renatofilho@787
  1312
renatofilho@787
  1313
  GST_LOG_OBJECT (dbin, "Checking with caps %" GST_PTR_FORMAT, caps);
renatofilho@787
  1314
renatofilho@787
  1315
  intersection = gst_caps_intersect (dbin->caps, caps);
renatofilho@787
  1316
renatofilho@787
  1317
  res = (!(gst_caps_is_empty (intersection)));
renatofilho@787
  1318
renatofilho@787
  1319
  gst_caps_unref (intersection);
renatofilho@787
  1320
renatofilho@787
  1321
  GST_LOG_OBJECT (dbin, "Caps are %sfinal caps", res ? "" : "not ");
renatofilho@787
  1322
renatofilho@787
  1323
  return res;
renatofilho@787
  1324
}
renatofilho@787
  1325
renatofilho@787
  1326
renatofilho@787
  1327
/****
renatofilho@787
  1328
 * GstDecodeGroup functions
renatofilho@787
  1329
 ****/
renatofilho@787
  1330
renatofilho@787
  1331
static void
renatofilho@787
  1332
multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group)
renatofilho@787
  1333
{
renatofilho@787
  1334
  GST_LOG_OBJECT (group->dbin, "multiqueue is full");
renatofilho@787
  1335
renatofilho@787
  1336
  /* if we haven't exposed the group, do it */
renatofilho@787
  1337
  DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1338
  gst_decode_group_expose (group);
renatofilho@787
  1339
  DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1340
}
renatofilho@787
  1341
renatofilho@787
  1342
static void
renatofilho@787
  1343
multi_queue_underrun_cb (GstElement * queue, GstDecodeGroup * group)
renatofilho@787
  1344
{
renatofilho@787
  1345
  GstDecodeBin *dbin = group->dbin;
renatofilho@787
  1346
renatofilho@787
  1347
  GST_LOG_OBJECT (dbin, "multiqueue is empty for group %p", group);
renatofilho@787
  1348
renatofilho@787
  1349
  /* Check if we need to activate another group */
renatofilho@787
  1350
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1351
  if ((group == dbin->activegroup) && dbin->groups) {
renatofilho@787
  1352
    GST_DEBUG_OBJECT (dbin, "Switching to new group");
renatofilho@787
  1353
    /* unexpose current active */
renatofilho@787
  1354
    gst_decode_group_hide (group);
renatofilho@787
  1355
renatofilho@787
  1356
    /* expose first group of groups */
renatofilho@787
  1357
    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
renatofilho@787
  1358
  }
renatofilho@787
  1359
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1360
}
renatofilho@787
  1361
renatofilho@787
  1362
/* gst_decode_group_new
renatofilho@787
  1363
 *
renatofilho@787
  1364
 * Creates a new GstDecodeGroup. It is up to the caller to add it to the list
renatofilho@787
  1365
 * of groups.
renatofilho@787
  1366
 */
renatofilho@787
  1367
static GstDecodeGroup *
renatofilho@787
  1368
gst_decode_group_new (GstDecodeBin * dbin)
renatofilho@787
  1369
{
renatofilho@787
  1370
  GstDecodeGroup *group;
renatofilho@787
  1371
  GstElement *mq;
renatofilho@787
  1372
renatofilho@787
  1373
  GST_LOG_OBJECT (dbin, "Creating new group");
renatofilho@787
  1374
renatofilho@787
  1375
  if (!(mq = gst_element_factory_make ("multiqueue", NULL))) {
renatofilho@787
  1376
    GST_WARNING ("Couldn't create multiqueue element");
renatofilho@787
  1377
    return NULL;
renatofilho@787
  1378
  }
renatofilho@787
  1379
renatofilho@787
  1380
  g_object_set (G_OBJECT (mq),
renatofilho@787
  1381
      "max-size-bytes", 2 * 1024 * 1024,
renatofilho@787
  1382
      "max-size-time", 5 * GST_SECOND, "max-size-buffers", 0, NULL);
renatofilho@787
  1383
renatofilho@787
  1384
  group = g_new0 (GstDecodeGroup, 1);
renatofilho@787
  1385
  group->lock = g_mutex_new ();
renatofilho@787
  1386
  group->dbin = dbin;
renatofilho@787
  1387
  group->multiqueue = mq;
renatofilho@787
  1388
  group->exposed = FALSE;
renatofilho@787
  1389
  group->drained = FALSE;
renatofilho@787
  1390
  group->blocked = FALSE;
renatofilho@787
  1391
  group->complete = FALSE;
renatofilho@787
  1392
  group->endpads = NULL;
renatofilho@787
  1393
renatofilho@787
  1394
  group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun",
renatofilho@787
  1395
      G_CALLBACK (multi_queue_overrun_cb), group);
renatofilho@787
  1396
  group->underrunsig = g_signal_connect (G_OBJECT (mq), "underrun",
renatofilho@787
  1397
      G_CALLBACK (multi_queue_underrun_cb), group);
renatofilho@787
  1398
renatofilho@787
  1399
  gst_bin_add (GST_BIN (dbin), group->multiqueue);
renatofilho@787
  1400
  gst_element_set_state (group->multiqueue, GST_STATE_PAUSED);
renatofilho@787
  1401
renatofilho@787
  1402
  GST_LOG_OBJECT (dbin, "Returning new group %p", group);
renatofilho@787
  1403
renatofilho@787
  1404
  return group;
renatofilho@787
  1405
}
renatofilho@787
  1406
renatofilho@787
  1407
/** get_current_group:
renatofilho@787
  1408
 *
renatofilho@787
  1409
 * Returns the current non-completed group.
renatofilho@787
  1410
 *
renatofilho@787
  1411
 * Returns NULL if no groups are available, or all groups are completed.
renatofilho@787
  1412
 */
renatofilho@787
  1413
static GstDecodeGroup *
renatofilho@787
  1414
get_current_group (GstDecodeBin * dbin)
renatofilho@787
  1415
{
renatofilho@787
  1416
  GList *tmp;
renatofilho@787
  1417
  GstDecodeGroup *group = NULL;
renatofilho@787
  1418
renatofilho@787
  1419
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1420
  for (tmp = dbin->groups; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1421
    GstDecodeGroup *this = (GstDecodeGroup *) tmp->data;
renatofilho@787
  1422
renatofilho@787
  1423
    GST_LOG_OBJECT (dbin, "group %p, complete:%d", this, this->complete);
renatofilho@787
  1424
renatofilho@787
  1425
    if (!this->complete) {
renatofilho@787
  1426
      group = this;
renatofilho@787
  1427
      break;
renatofilho@787
  1428
    }
renatofilho@787
  1429
  }
renatofilho@787
  1430
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1431
renatofilho@787
  1432
  GST_LOG_OBJECT (dbin, "Returning group %p", group);
renatofilho@787
  1433
renatofilho@787
  1434
  return group;
renatofilho@787
  1435
}
renatofilho@787
  1436
renatofilho@787
  1437
static gboolean
renatofilho@787
  1438
group_demuxer_event_probe (GstPad * pad, GstEvent * event,
renatofilho@787
  1439
    GstDecodeGroup * group)
renatofilho@787
  1440
{
renatofilho@787
  1441
  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
renatofilho@787
  1442
    GST_DEBUG_OBJECT (group->dbin,
renatofilho@787
  1443
        "Got EOS on group input pads, exposing group if it wasn't before");
renatofilho@787
  1444
    DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1445
    gst_decode_group_expose (group);
renatofilho@787
  1446
    DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1447
  }
renatofilho@787
  1448
  return TRUE;
renatofilho@787
  1449
}
renatofilho@787
  1450
renatofilho@787
  1451
/* gst_decode_group_control_demuxer_pad
renatofilho@787
  1452
 *
renatofilho@787
  1453
 * Adds a new demuxer srcpad to the given group.
renatofilho@787
  1454
 *
renatofilho@787
  1455
 * Returns the srcpad of the multiqueue corresponding the given pad.
renatofilho@787
  1456
 * Returns NULL if there was an error.
renatofilho@787
  1457
 */
renatofilho@787
  1458
static GstPad *
renatofilho@787
  1459
gst_decode_group_control_demuxer_pad (GstDecodeGroup * group, GstPad * pad)
renatofilho@787
  1460
{
renatofilho@787
  1461
  GstPad *srcpad, *sinkpad;
renatofilho@787
  1462
  gchar *nb, *sinkname, *srcname;
renatofilho@787
  1463
renatofilho@787
  1464
  GST_LOG ("group:%p pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
renatofilho@787
  1465
renatofilho@787
  1466
  srcpad = NULL;
renatofilho@787
  1467
renatofilho@787
  1468
  if (!(sinkpad = gst_element_get_pad (group->multiqueue, "sink%d"))) {
renatofilho@787
  1469
    GST_ERROR ("Couldn't get sinkpad from multiqueue");
renatofilho@787
  1470
    return NULL;
renatofilho@787
  1471
  }
renatofilho@787
  1472
renatofilho@787
  1473
  if ((gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)) {
renatofilho@787
  1474
    GST_ERROR ("Couldn't link demuxer and multiqueue");
renatofilho@787
  1475
    goto beach;
renatofilho@787
  1476
  }
renatofilho@787
  1477
renatofilho@787
  1478
  sinkname = gst_pad_get_name (sinkpad);
renatofilho@787
  1479
  nb = sinkname + 4;
renatofilho@787
  1480
  srcname = g_strdup_printf ("src%s", nb);
renatofilho@787
  1481
  g_free (sinkname);
renatofilho@787
  1482
renatofilho@787
  1483
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1484
renatofilho@787
  1485
  if (!(srcpad = gst_element_get_pad (group->multiqueue, srcname))) {
renatofilho@787
  1486
    GST_ERROR ("Couldn't get srcpad %s from multiqueue", srcname);
renatofilho@787
  1487
    goto chiringuito;
renatofilho@787
  1488
  }
renatofilho@787
  1489
renatofilho@787
  1490
  /* connect event handler on pad to intercept EOS events */
renatofilho@787
  1491
  gst_pad_add_event_probe (pad, G_CALLBACK (group_demuxer_event_probe), group);
renatofilho@787
  1492
renatofilho@787
  1493
chiringuito:
renatofilho@787
  1494
  g_free (srcname);
renatofilho@787
  1495
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1496
renatofilho@787
  1497
beach:
renatofilho@787
  1498
  gst_object_unref (sinkpad);
renatofilho@787
  1499
  return srcpad;
renatofilho@787
  1500
}
renatofilho@787
  1501
renatofilho@787
  1502
static gboolean
renatofilho@787
  1503
gst_decode_group_control_source_pad (GstDecodeGroup * group, GstPad * pad)
renatofilho@787
  1504
{
renatofilho@787
  1505
  GstDecodePad *dpad;
renatofilho@787
  1506
renatofilho@787
  1507
  g_return_val_if_fail (group != NULL, FALSE);
renatofilho@787
  1508
renatofilho@787
  1509
  GST_LOG ("group:%p , pad %s:%s", group, GST_DEBUG_PAD_NAME (pad));
renatofilho@787
  1510
renatofilho@787
  1511
  /* FIXME : check if pad is already controlled */
renatofilho@787
  1512
renatofilho@787
  1513
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1514
renatofilho@787
  1515
  /* Create GstDecodePad for the pad */
renatofilho@787
  1516
  dpad = gst_decode_pad_new (group, pad, TRUE);
renatofilho@787
  1517
renatofilho@787
  1518
  group->endpads = g_list_append (group->endpads, dpad);
renatofilho@787
  1519
renatofilho@787
  1520
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1521
renatofilho@787
  1522
  return TRUE;
renatofilho@787
  1523
}
renatofilho@787
  1524
renatofilho@787
  1525
/* gst_decode_group_check_if_blocked:
renatofilho@787
  1526
 *
renatofilho@787
  1527
 * Call this when one of the pads blocked status has changed.
renatofilho@787
  1528
 * If the group is complete and blocked, the group will be marked as blocked
renatofilho@787
  1529
 * and will ghost/expose all pads on decodebin if the group is the current one.
renatofilho@787
  1530
 *
renatofilho@787
  1531
 * Call with the group lock taken ! MT safe
renatofilho@787
  1532
 */
renatofilho@787
  1533
static void
renatofilho@787
  1534
gst_decode_group_check_if_blocked (GstDecodeGroup * group)
renatofilho@787
  1535
{
renatofilho@787
  1536
  GList *tmp;
renatofilho@787
  1537
  gboolean blocked = TRUE;
renatofilho@787
  1538
renatofilho@787
  1539
  GST_LOG ("group : %p , ->complete:%d , ->nbdynamic:%d",
renatofilho@787
  1540
      group, group->complete, group->nbdynamic);
renatofilho@787
  1541
renatofilho@787
  1542
  /* 1. don't do anything if group is not complete */
renatofilho@787
  1543
  if (!group->complete || group->nbdynamic) {
renatofilho@787
  1544
    GST_DEBUG_OBJECT (group->dbin, "Group isn't complete yet");
renatofilho@787
  1545
    return;
renatofilho@787
  1546
  }
renatofilho@787
  1547
renatofilho@787
  1548
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1549
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1550
renatofilho@787
  1551
    if (!dpad->blocked) {
renatofilho@787
  1552
      blocked = FALSE;
renatofilho@787
  1553
      break;
renatofilho@787
  1554
    }
renatofilho@787
  1555
  }
renatofilho@787
  1556
renatofilho@787
  1557
  /* 2. Update status of group */
renatofilho@787
  1558
  group->blocked = blocked;
renatofilho@787
  1559
  GST_LOG ("group is blocked:%d", blocked);
renatofilho@787
  1560
renatofilho@787
  1561
  /* 3. don't do anything if not blocked completely */
renatofilho@787
  1562
  if (!blocked)
renatofilho@787
  1563
    return;
renatofilho@787
  1564
renatofilho@787
  1565
  /* 4. if we're the current group, expose pads */
renatofilho@787
  1566
  DECODE_BIN_LOCK (group->dbin);
renatofilho@787
  1567
  if (!gst_decode_group_expose (group))
renatofilho@787
  1568
    GST_WARNING_OBJECT (group->dbin, "Couldn't expose group");
renatofilho@787
  1569
  DECODE_BIN_UNLOCK (group->dbin);
renatofilho@787
  1570
}
renatofilho@787
  1571
renatofilho@787
  1572
static void
renatofilho@787
  1573
gst_decode_group_check_if_drained (GstDecodeGroup * group)
renatofilho@787
  1574
{
renatofilho@787
  1575
  GList *tmp;
renatofilho@787
  1576
  GstDecodeBin *dbin = group->dbin;
renatofilho@787
  1577
  gboolean drained = TRUE;
renatofilho@787
  1578
renatofilho@787
  1579
  GST_LOG ("group : %p", group);
renatofilho@787
  1580
renatofilho@787
  1581
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1582
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1583
renatofilho@787
  1584
    GST_LOG ("testing dpad %p", dpad);
renatofilho@787
  1585
renatofilho@787
  1586
    if (!dpad->drained) {
renatofilho@787
  1587
      drained = FALSE;
renatofilho@787
  1588
      break;
renatofilho@787
  1589
    }
renatofilho@787
  1590
  }
renatofilho@787
  1591
renatofilho@787
  1592
  group->drained = drained;
renatofilho@787
  1593
  GST_LOG ("group is drained");
renatofilho@787
  1594
renatofilho@787
  1595
  if (!drained)
renatofilho@787
  1596
    return;
renatofilho@787
  1597
renatofilho@787
  1598
  DECODE_BIN_LOCK (dbin);
renatofilho@787
  1599
  if ((group == dbin->activegroup) && dbin->groups) {
renatofilho@787
  1600
    GST_DEBUG_OBJECT (dbin, "Switching to new group");
renatofilho@787
  1601
renatofilho@787
  1602
    gst_decode_group_hide (group);
renatofilho@787
  1603
renatofilho@787
  1604
    gst_decode_group_expose ((GstDecodeGroup *) dbin->groups->data);
renatofilho@787
  1605
  }
renatofilho@787
  1606
  DECODE_BIN_UNLOCK (dbin);
renatofilho@787
  1607
}
renatofilho@787
  1608
renatofilho@787
  1609
/* sort_end_pads:
renatofilho@787
  1610
 * GCompareFunc to use with lists of GstPad.
renatofilho@787
  1611
 * Sorts pads by mime type.
renatofilho@787
  1612
 * First video (raw, then non-raw), then audio (raw, then non-raw),
renatofilho@787
  1613
 * then others.
renatofilho@787
  1614
 *
renatofilho@787
  1615
 * Return: negative if a<b, 0 if a==b, positive if a>b
renatofilho@787
  1616
 */
renatofilho@787
  1617
renatofilho@787
  1618
static gint
renatofilho@787
  1619
sort_end_pads (GstDecodePad * da, GstDecodePad * db)
renatofilho@787
  1620
{
renatofilho@787
  1621
  GstPad *a, *b;
renatofilho@787
  1622
  gint va, vb;
renatofilho@787
  1623
  GstCaps *capsa, *capsb;
renatofilho@787
  1624
  GstStructure *sa, *sb;
renatofilho@787
  1625
  const gchar *namea, *nameb;
renatofilho@787
  1626
renatofilho@787
  1627
  a = da->pad;
renatofilho@787
  1628
  b = db->pad;
renatofilho@787
  1629
renatofilho@787
  1630
  capsa = gst_pad_get_caps (a);
renatofilho@787
  1631
  capsb = gst_pad_get_caps (b);
renatofilho@787
  1632
renatofilho@787
  1633
  sa = gst_caps_get_structure ((const GstCaps *) capsa, 0);
renatofilho@787
  1634
  sb = gst_caps_get_structure ((const GstCaps *) capsb, 0);
renatofilho@787
  1635
renatofilho@787
  1636
  namea = gst_structure_get_name (sa);
renatofilho@787
  1637
  nameb = gst_structure_get_name (sb);
renatofilho@787
  1638
renatofilho@787
  1639
  if (g_strrstr (namea, "video/x-raw-"))
renatofilho@787
  1640
    va = 0;
renatofilho@787
  1641
  else if (g_strrstr (namea, "video/"))
renatofilho@787
  1642
    va = 1;
renatofilho@787
  1643
  else if (g_strrstr (namea, "audio/x-raw"))
renatofilho@787
  1644
    va = 2;
renatofilho@787
  1645
  else if (g_strrstr (namea, "audio/"))
renatofilho@787
  1646
    va = 3;
renatofilho@787
  1647
  else
renatofilho@787
  1648
    va = 4;
renatofilho@787
  1649
renatofilho@787
  1650
  if (g_strrstr (nameb, "video/x-raw-"))
renatofilho@787
  1651
    vb = 0;
renatofilho@787
  1652
  else if (g_strrstr (nameb, "video/"))
renatofilho@787
  1653
    vb = 1;
renatofilho@787
  1654
  else if (g_strrstr (nameb, "audio/x-raw"))
renatofilho@787
  1655
    vb = 2;
renatofilho@787
  1656
  else if (g_strrstr (nameb, "audio/"))
renatofilho@787
  1657
    vb = 3;
renatofilho@787
  1658
  else
renatofilho@787
  1659
    vb = 4;
renatofilho@787
  1660
renatofilho@787
  1661
  gst_caps_unref (capsa);
renatofilho@787
  1662
  gst_caps_unref (capsb);
renatofilho@787
  1663
renatofilho@787
  1664
  return va - vb;
renatofilho@787
  1665
}
renatofilho@787
  1666
renatofilho@787
  1667
/* gst_decode_group_expose:
renatofilho@787
  1668
 *
renatofilho@787
  1669
 * Expose this group's pads.
renatofilho@787
  1670
 *
renatofilho@787
  1671
 * Not MT safe, please take the group lock
renatofilho@787
  1672
 */
renatofilho@787
  1673
renatofilho@787
  1674
static gboolean
renatofilho@787
  1675
gst_decode_group_expose (GstDecodeGroup * group)
renatofilho@787
  1676
{
renatofilho@787
  1677
  GList *tmp;
renatofilho@787
  1678
  GList *next = NULL;
renatofilho@787
  1679
renatofilho@787
  1680
  if (group->dbin->activegroup) {
renatofilho@787
  1681
    GST_DEBUG_OBJECT (group->dbin, "A group is already active and exposed");
renatofilho@787
  1682
    return TRUE;
renatofilho@787
  1683
  }
renatofilho@787
  1684
renatofilho@787
  1685
  if (group->dbin->activegroup == group) {
renatofilho@787
  1686
    GST_WARNING ("Group %p is already exposed", group);
renatofilho@787
  1687
    return TRUE;
renatofilho@787
  1688
  }
renatofilho@787
  1689
renatofilho@787
  1690
  if (!group->dbin->groups
renatofilho@787
  1691
      || (group != (GstDecodeGroup *) group->dbin->groups->data)) {
renatofilho@787
  1692
    GST_WARNING ("Group %p is not the first group to expose", group);
renatofilho@787
  1693
    return FALSE;
renatofilho@787
  1694
  }
renatofilho@787
  1695
renatofilho@787
  1696
  if (group->nbdynamic) {
renatofilho@787
  1697
    GST_WARNING ("Group %p still has %d dynamic objects, not exposing yet",
renatofilho@787
  1698
        group, group->nbdynamic);
renatofilho@787
  1699
    return FALSE;
renatofilho@787
  1700
  }
renatofilho@787
  1701
renatofilho@787
  1702
  GST_LOG ("Exposing group %p", group);
renatofilho@787
  1703
renatofilho@787
  1704
  /* re-order pads : video, then audio, then others */
renatofilho@787
  1705
  group->endpads = g_list_sort (group->endpads, (GCompareFunc) sort_end_pads);
renatofilho@787
  1706
renatofilho@787
  1707
  /* Expose pads */
renatofilho@787
  1708
renatofilho@787
  1709
  for (tmp = group->endpads; tmp; tmp = next) {
renatofilho@787
  1710
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1711
    gchar *padname;
renatofilho@787
  1712
    GstPad *ghost;
renatofilho@787
  1713
renatofilho@787
  1714
    next = g_list_next (tmp);
renatofilho@787
  1715
renatofilho@787
  1716
    /* 1. ghost pad */
renatofilho@787
  1717
    padname = g_strdup_printf ("src%d", group->dbin->nbpads);
renatofilho@787
  1718
    group->dbin->nbpads++;
renatofilho@787
  1719
renatofilho@787
  1720
    GST_LOG_OBJECT (group->dbin, "About to expose pad %s:%s",
renatofilho@787
  1721
        GST_DEBUG_PAD_NAME (dpad->pad));
renatofilho@787
  1722
renatofilho@787
  1723
    ghost = gst_ghost_pad_new (padname, dpad->pad);
renatofilho@787
  1724
    gst_pad_set_active (ghost, TRUE);
renatofilho@787
  1725
    gst_element_add_pad (GST_ELEMENT (group->dbin), ghost);
renatofilho@787
  1726
    group->ghosts = g_list_append (group->ghosts, ghost);
renatofilho@787
  1727
renatofilho@787
  1728
    g_free (padname);
renatofilho@787
  1729
renatofilho@787
  1730
    /* 2. emit signal */
renatofilho@787
  1731
    GST_DEBUG_OBJECT (group->dbin, "emitting new-decoded-pad");
renatofilho@787
  1732
    g_signal_emit (G_OBJECT (group->dbin),
renatofilho@787
  1733
        gst_decode_bin_signals[SIGNAL_NEW_DECODED_PAD], 0, ghost,
renatofilho@787
  1734
        (next == NULL));
renatofilho@787
  1735
    GST_DEBUG_OBJECT (group->dbin, "emitted new-decoded-pad");
renatofilho@787
  1736
renatofilho@787
  1737
    /* 3. Unblock internal  pad */
renatofilho@787
  1738
    GST_DEBUG_OBJECT (dpad->pad, "unblocking");
renatofilho@787
  1739
    gst_pad_set_blocked_async (dpad->pad, FALSE,
renatofilho@787
  1740
        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
renatofilho@787
  1741
    GST_DEBUG_OBJECT (dpad->pad, "unblocked");
renatofilho@787
  1742
renatofilho@787
  1743
  }
renatofilho@787
  1744
renatofilho@787
  1745
  group->dbin->activegroup = group;
renatofilho@787
  1746
renatofilho@787
  1747
  /* pop off the first group */
renatofilho@787
  1748
  group->dbin->groups =
renatofilho@787
  1749
      g_list_delete_link (group->dbin->groups, group->dbin->groups);
renatofilho@787
  1750
renatofilho@787
  1751
  remove_fakesink (group->dbin);
renatofilho@787
  1752
renatofilho@787
  1753
  group->exposed = TRUE;
renatofilho@787
  1754
renatofilho@787
  1755
  GST_LOG_OBJECT (group->dbin, "signalling no-more-pads");
renatofilho@787
  1756
  gst_element_no_more_pads (GST_ELEMENT (group->dbin));
renatofilho@787
  1757
renatofilho@787
  1758
  GST_LOG_OBJECT (group->dbin, "Group %p exposed", group);
renatofilho@787
  1759
  return TRUE;
renatofilho@787
  1760
}
renatofilho@787
  1761
renatofilho@787
  1762
static void
renatofilho@787
  1763
gst_decode_group_hide (GstDecodeGroup * group)
renatofilho@787
  1764
{
renatofilho@787
  1765
  GList *tmp;
renatofilho@787
  1766
renatofilho@787
  1767
  GST_LOG ("Hiding group %p", group);
renatofilho@787
  1768
renatofilho@787
  1769
  if (group != group->dbin->activegroup) {
renatofilho@787
  1770
    GST_WARNING ("This group is not the active one, aborting");
renatofilho@787
  1771
    return;
renatofilho@787
  1772
  }
renatofilho@787
  1773
renatofilho@787
  1774
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1775
renatofilho@787
  1776
  /* Remove ghost pads */
renatofilho@787
  1777
  for (tmp = group->ghosts; tmp; tmp = g_list_next (tmp))
renatofilho@787
  1778
    gst_element_remove_pad (GST_ELEMENT (group->dbin), (GstPad *) tmp->data);
renatofilho@787
  1779
renatofilho@787
  1780
  g_list_free (group->ghosts);
renatofilho@787
  1781
  group->ghosts = NULL;
renatofilho@787
  1782
renatofilho@787
  1783
  group->exposed = FALSE;
renatofilho@787
  1784
renatofilho@787
  1785
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1786
renatofilho@787
  1787
  group->dbin->activegroup = NULL;
renatofilho@787
  1788
  group->dbin->oldgroups = g_list_append (group->dbin->oldgroups, group);
renatofilho@787
  1789
}
renatofilho@787
  1790
renatofilho@787
  1791
static void
renatofilho@787
  1792
deactivate_free_recursive (GstDecodeGroup * group, GstElement * element)
renatofilho@787
  1793
{
renatofilho@787
  1794
  GstIterator *it;
renatofilho@787
  1795
  GstIteratorResult res;
renatofilho@787
  1796
  gpointer point;
renatofilho@787
  1797
renatofilho@787
  1798
  GST_LOG ("element:%s", GST_ELEMENT_NAME (element));
renatofilho@787
  1799
renatofilho@787
  1800
  /* call on downstream elements */
renatofilho@787
  1801
  it = gst_element_iterate_src_pads (element);
renatofilho@787
  1802
renatofilho@787
  1803
restart:
renatofilho@787
  1804
renatofilho@787
  1805
  while (1) {
renatofilho@787
  1806
    res = gst_iterator_next (it, &point);
renatofilho@787
  1807
    switch (res) {
renatofilho@787
  1808
      case GST_ITERATOR_DONE:
renatofilho@787
  1809
        goto done;
renatofilho@787
  1810
      case GST_ITERATOR_RESYNC:
renatofilho@787
  1811
        gst_iterator_resync (it);
renatofilho@787
  1812
        goto restart;
renatofilho@787
  1813
      case GST_ITERATOR_ERROR:
renatofilho@787
  1814
      {
renatofilho@787
  1815
        GST_WARNING ("Had an error while iterating source pads of element: %s",
renatofilho@787
  1816
            GST_ELEMENT_NAME (element));
renatofilho@787
  1817
        goto beach;
renatofilho@787
  1818
      }
renatofilho@787
  1819
      case GST_ITERATOR_OK:
renatofilho@787
  1820
      {
renatofilho@787
  1821
        GstPad *pad = GST_PAD (point);
renatofilho@787
  1822
        GstPad *peerpad = NULL;
renatofilho@787
  1823
renatofilho@787
  1824
        if ((peerpad = gst_pad_get_peer (pad))) {
renatofilho@787
  1825
          GstObject *parent = gst_pad_get_parent (peerpad);
renatofilho@787
  1826
renatofilho@787
  1827
          if (parent && GST_IS_ELEMENT (parent))
renatofilho@787
  1828
            deactivate_free_recursive (group, GST_ELEMENT (parent));
renatofilho@787
  1829
          if (parent)
renatofilho@787
  1830
            gst_object_unref (parent);
renatofilho@787
  1831
        }
renatofilho@787
  1832
      }
renatofilho@787
  1833
        break;
renatofilho@787
  1834
      default:
renatofilho@787
  1835
        break;
renatofilho@787
  1836
    }
renatofilho@787
  1837
  }
renatofilho@787
  1838
renatofilho@787
  1839
done:
renatofilho@787
  1840
  gst_element_set_state (element, GST_STATE_NULL);
renatofilho@787
  1841
  gst_bin_remove (GST_BIN (group->dbin), element);
renatofilho@787
  1842
renatofilho@787
  1843
beach:
renatofilho@787
  1844
  gst_iterator_free (it);
renatofilho@787
  1845
renatofilho@787
  1846
  return;
renatofilho@787
  1847
}
renatofilho@787
  1848
renatofilho@787
  1849
static void
renatofilho@787
  1850
gst_decode_group_free (GstDecodeGroup * group)
renatofilho@787
  1851
{
renatofilho@787
  1852
  GList *tmp;
renatofilho@787
  1853
renatofilho@787
  1854
  GST_LOG ("group %p", group);
renatofilho@787
  1855
renatofilho@787
  1856
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1857
  /* Clear all GstDecodePad */
renatofilho@787
  1858
  for (tmp = group->endpads; tmp; tmp = g_list_next (tmp)) {
renatofilho@787
  1859
    GstDecodePad *dpad = (GstDecodePad *) tmp->data;
renatofilho@787
  1860
renatofilho@787
  1861
    g_free (dpad);
renatofilho@787
  1862
  }
renatofilho@787
  1863
  g_list_free (group->endpads);
renatofilho@787
  1864
  group->endpads = NULL;
renatofilho@787
  1865
renatofilho@787
  1866
  /* disconnect signal handlers on multiqueue */
renatofilho@787
  1867
  g_signal_handler_disconnect (group->multiqueue, group->underrunsig);
renatofilho@787
  1868
  g_signal_handler_disconnect (group->multiqueue, group->overrunsig);
renatofilho@787
  1869
renatofilho@787
  1870
  /* remove all elements */
renatofilho@787
  1871
  deactivate_free_recursive (group, group->multiqueue);
renatofilho@787
  1872
renatofilho@787
  1873
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1874
renatofilho@787
  1875
  g_mutex_free (group->lock);
renatofilho@787
  1876
  g_free (group);
renatofilho@787
  1877
}
renatofilho@787
  1878
renatofilho@787
  1879
/* gst_decode_group_set_complete:
renatofilho@787
  1880
 *
renatofilho@787
  1881
 * Mark the group as complete. This means no more streams will be controlled
renatofilho@787
  1882
 * through this group.
renatofilho@787
  1883
 *
renatofilho@787
  1884
 * MT safe
renatofilho@787
  1885
 */
renatofilho@787
  1886
static void
renatofilho@787
  1887
gst_decode_group_set_complete (GstDecodeGroup * group)
renatofilho@787
  1888
{
renatofilho@787
  1889
  GST_LOG_OBJECT (group->dbin, "Setting group %p to COMPLETE", group);
renatofilho@787
  1890
renatofilho@787
  1891
  GROUP_MUTEX_LOCK (group);
renatofilho@787
  1892
  group->complete = TRUE;
renatofilho@787
  1893
  gst_decode_group_check_if_blocked (group);
renatofilho@787
  1894
  GROUP_MUTEX_UNLOCK (group);
renatofilho@787
  1895
}
renatofilho@787
  1896
renatofilho@787
  1897
renatofilho@787
  1898
renatofilho@787
  1899
/*************************
renatofilho@787
  1900
 * GstDecodePad functions
renatofilho@787
  1901
 *************************/
renatofilho@787
  1902
renatofilho@787
  1903
static void
renatofilho@787
  1904
source_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodePad * dpad)
renatofilho@787
  1905
{
renatofilho@787
  1906
  GST_LOG_OBJECT (pad, "blocked:%d , dpad:%p, dpad->group:%p",
renatofilho@787
  1907
      blocked, dpad, dpad->group);
renatofilho@787
  1908
renatofilho@787
  1909
  /* Update this GstDecodePad status */
renatofilho@787
  1910
  dpad->blocked = blocked;
renatofilho@787
  1911
renatofilho@787
  1912
  if (blocked) {
renatofilho@787
  1913
    GROUP_MUTEX_LOCK (dpad->group);
renatofilho@787
  1914
    gst_decode_group_check_if_blocked (dpad->group);
renatofilho@787
  1915
    GROUP_MUTEX_UNLOCK (dpad->group);
renatofilho@787
  1916
  }
renatofilho@787
  1917
}
renatofilho@787
  1918
renatofilho@787
  1919
static gboolean
renatofilho@787
  1920
source_pad_event_probe (GstPad * pad, GstEvent * event, GstDecodePad * dpad)
renatofilho@787
  1921
{
renatofilho@787
  1922
  GST_LOG_OBJECT (pad, "%s dpad:%p", GST_EVENT_TYPE_NAME (event), dpad);
renatofilho@787
  1923
renatofilho@787
  1924
  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
renatofilho@787
  1925
    /* Set our pad as drained */
renatofilho@787
  1926
    dpad->drained = TRUE;
renatofilho@787
  1927
renatofilho@787
  1928
    /* Check if all pads are drained */
renatofilho@787
  1929
    gst_decode_group_check_if_drained (dpad->group);
renatofilho@787
  1930
  }
renatofilho@787
  1931
renatofilho@787
  1932
  return TRUE;
renatofilho@787
  1933
}
renatofilho@787
  1934
renatofilho@787
  1935
/*gst_decode_pad_new:
renatofilho@787
  1936
 *
renatofilho@787
  1937
 * Creates a new GstDecodePad for the given pad.
renatofilho@787
  1938
 * If block is TRUE, Sets the pad blocking asynchronously
renatofilho@787
  1939
 */
renatofilho@787
  1940
renatofilho@787
  1941
static GstDecodePad *
renatofilho@787
  1942
gst_decode_pad_new (GstDecodeGroup * group, GstPad * pad, gboolean block)
renatofilho@787
  1943
{
renatofilho@787
  1944
  GstDecodePad *dpad;
renatofilho@787
  1945
renatofilho@787
  1946
  dpad = g_new0 (GstDecodePad, 1);
renatofilho@787
  1947
  dpad->pad = pad;
renatofilho@787
  1948
  dpad->group = group;
renatofilho@787
  1949
  dpad->blocked = FALSE;
renatofilho@787
  1950
  dpad->drained = TRUE;
renatofilho@787
  1951
renatofilho@787
  1952
  if (block)
renatofilho@787
  1953
    gst_pad_set_blocked_async (pad, TRUE,
renatofilho@787
  1954
        (GstPadBlockCallback) source_pad_blocked_cb, dpad);
renatofilho@787
  1955
  gst_pad_add_event_probe (pad, G_CALLBACK (source_pad_event_probe), dpad);
renatofilho@787
  1956
  return dpad;
renatofilho@787
  1957
}
renatofilho@787
  1958
renatofilho@787
  1959
renatofilho@787
  1960
/*****
renatofilho@787
  1961
 * Element add/remove
renatofilho@787
  1962
 *****/
renatofilho@787
  1963
renatofilho@787
  1964
/*
renatofilho@787
  1965
 * add_fakesink / remove_fakesink
renatofilho@787
  1966
 *
renatofilho@787
  1967
 * We use a sink so that the parent ::change_state returns GST_STATE_CHANGE_ASYNC
renatofilho@787
  1968
 * when that sink is present (since it's not connected to anything it will 
renatofilho@787
  1969
 * always return GST_STATE_CHANGE_ASYNC).
renatofilho@787
  1970
 *
renatofilho@787
  1971
 * But this is an ugly way of achieving this goal.
renatofilho@787
  1972
 * Ideally, we shouldn't use a sink and just return GST_STATE_CHANGE_ASYNC in
renatofilho@787
  1973
 * our ::change_state if we have not exposed the active group.
renatofilho@787
  1974
 * We also need to override ::get_state to fake the asynchronous behaviour.
renatofilho@787
  1975
 * Once the active group is exposed, we would then post a
renatofilho@787
  1976
 * GST_MESSAGE_STATE_DIRTY and return GST_STATE_CHANGE_SUCCESS (which will call
renatofilho@787
  1977
 * ::get_state .
renatofilho@787
  1978
 */
renatofilho@787
  1979
renatofilho@787
  1980
static gboolean
renatofilho@787
  1981
add_fakesink (GstDecodeBin * decode_bin)
renatofilho@787
  1982
{
renatofilho@787
  1983
  GST_DEBUG_OBJECT (decode_bin, "Adding the fakesink");
renatofilho@787
  1984
renatofilho@787
  1985
  if (decode_bin->fakesink)
renatofilho@787
  1986
    return TRUE;
renatofilho@787
  1987
renatofilho@787
  1988
  decode_bin->fakesink =
renatofilho@787
  1989
      gst_element_factory_make ("fakesink", "async-fakesink");
renatofilho@787
  1990
  if (!decode_bin->fakesink)
renatofilho@787
  1991
    goto no_fakesink;
renatofilho@787
  1992
renatofilho@787
  1993
  /* hacky, remove sink flag, we don't want our decodebin to become a sink
renatofilho@787
  1994
   * just because we add a fakesink element to make us ASYNC */
renatofilho@787
  1995
  GST_OBJECT_FLAG_UNSET (decode_bin->fakesink, GST_ELEMENT_IS_SINK);
renatofilho@787
  1996
renatofilho@787
  1997
  if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink))
renatofilho@787
  1998
    goto could_not_add;
renatofilho@787
  1999
renatofilho@787
  2000
  return TRUE;
renatofilho@787
  2001
renatofilho@787
  2002
  /* ERRORS */
renatofilho@787
  2003
no_fakesink:
renatofilho@787
  2004
  {
renatofilho@787
  2005
    g_warning ("can't find fakesink element, decodebin will not work");
renatofilho@787
  2006
    return FALSE;
renatofilho@787
  2007
  }
renatofilho@787
  2008
could_not_add:
renatofilho@787
  2009
  {
renatofilho@787
  2010
    g_warning ("Could not add fakesink to decodebin, decodebin will not work");
renatofilho@787
  2011
    gst_object_unref (decode_bin->fakesink);
renatofilho@787
  2012
    decode_bin->fakesink = NULL;
renatofilho@787
  2013
    return FALSE;
renatofilho@787
  2014
  }
renatofilho@787
  2015
}
renatofilho@787
  2016
renatofilho@787
  2017
static void
renatofilho@787
  2018
remove_fakesink (GstDecodeBin * decode_bin)
renatofilho@787
  2019
{
renatofilho@787
  2020
  if (decode_bin->fakesink == NULL)
renatofilho@787
  2021
    return;
renatofilho@787
  2022
renatofilho@787
  2023
  GST_DEBUG_OBJECT (decode_bin, "Removing the fakesink");
renatofilho@787
  2024
renatofilho@787
  2025
  gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
renatofilho@787
  2026
  gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
renatofilho@787
  2027
  decode_bin->fakesink = NULL;
renatofilho@787
  2028
renatofilho@787
  2029
  gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
renatofilho@787
  2030
      gst_message_new_state_dirty (GST_OBJECT_CAST (decode_bin)));
renatofilho@787
  2031
}
renatofilho@787
  2032
renatofilho@787
  2033
/*****
renatofilho@787
  2034
 * convenience functions
renatofilho@787
  2035
 *****/
renatofilho@787
  2036
renatofilho@787
  2037
/* find_sink_pad
renatofilho@787
  2038
 *
renatofilho@787
  2039
 * Returns the first sink pad of the given element, or NULL if it doesn't have
renatofilho@787
  2040
 * any.
renatofilho@787
  2041
 */
renatofilho@787
  2042
renatofilho@787
  2043
static GstPad *
renatofilho@787
  2044
find_sink_pad (GstElement * element)
renatofilho@787
  2045
{
renatofilho@787
  2046
  GstIterator *it;
renatofilho@787
  2047
  GstPad *pad = NULL;
renatofilho@787
  2048
  gpointer point;
renatofilho@787
  2049
renatofilho@787
  2050
  it = gst_element_iterate_sink_pads (element);
renatofilho@787
  2051
renatofilho@787
  2052
  if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
renatofilho@787
  2053
    pad = (GstPad *) point;
renatofilho@787
  2054
renatofilho@787
  2055
  gst_iterator_free (it);
renatofilho@787
  2056
renatofilho@787
  2057
  return pad;
renatofilho@787
  2058
}
renatofilho@787
  2059
renatofilho@787
  2060
static GstStateChangeReturn
renatofilho@787
  2061
gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
renatofilho@787
  2062
{
renatofilho@787
  2063
  GstStateChangeReturn ret;
renatofilho@787
  2064
  GstDecodeBin *dbin = GST_DECODE_BIN (element);
renatofilho@787
  2065
renatofilho@787
  2066
  switch (transition) {
renatofilho@787
  2067
    case GST_STATE_CHANGE_NULL_TO_READY:
renatofilho@787
  2068
      if (dbin->typefind == NULL)
renatofilho@787
  2069
        goto missing_typefind;
renatofilho@787
  2070
      break;
renatofilho@787
  2071
    case GST_STATE_CHANGE_READY_TO_PAUSED:{
renatofilho@787
  2072
      if (!add_fakesink (dbin))
renatofilho@787
  2073
        goto missing_fakesink;
renatofilho@787
  2074
      break;
renatofilho@787
  2075
    }
renatofilho@787
  2076
    default:
renatofilho@787
  2077
      break;
renatofilho@787
  2078
  }
renatofilho@787
  2079
renatofilho@787
  2080
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
renatofilho@787
  2081
renatofilho@787
  2082
  /* FIXME : put some cleanup functions here.. if needed */
renatofilho@787
  2083
renatofilho@787
  2084
  return ret;
renatofilho@787
  2085
renatofilho@787
  2086
/* ERRORS */
renatofilho@787
  2087
missing_typefind:
renatofilho@787
  2088
  {
renatofilho@787
  2089
    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no typefind!"));
renatofilho@787
  2090
    return GST_STATE_CHANGE_FAILURE;
renatofilho@787
  2091
  }
renatofilho@787
  2092
missing_fakesink:
renatofilho@787
  2093
  {
renatofilho@787
  2094
    GST_ELEMENT_ERROR (dbin, CORE, MISSING_PLUGIN, (NULL), ("no fakesink!"));
renatofilho@787
  2095
    return GST_STATE_CHANGE_FAILURE;
renatofilho@787
  2096
  }
renatofilho@787
  2097
}
renatofilho@787
  2098
renatofilho@787
  2099
static gboolean
renatofilho@787
  2100
plugin_init (GstPlugin * plugin)
renatofilho@787
  2101
{
renatofilho@787
  2102
  GST_DEBUG_CATEGORY_INIT (gst_decode_bin_debug, "decodebin2", 0,
renatofilho@787
  2103
      "decoder bin");
renatofilho@787
  2104
renatofilho@787
  2105
  return gst_element_register (plugin, "decodebin2", GST_RANK_NONE,
renatofilho@787
  2106
      GST_TYPE_DECODE_BIN);
renatofilho@787
  2107
}
renatofilho@787
  2108
renatofilho@787
  2109
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
renatofilho@787
  2110
    GST_VERSION_MINOR,
renatofilho@787
  2111
    "decodebin2",
renatofilho@787
  2112
    "decoder bin newer version", plugin_init, VERSION, GST_LICENSE,
renatofilho@787
  2113
    GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)