@@ -183,6 +183,13 @@ struct _GstBinPrivate
183
183
* hits this number */
184
184
gint numchildren_use_hash ;
185
185
186
+ /* keep tabs on our childrens properties */
187
+ gint num_is_sink ;
188
+ gint num_is_src ;
189
+ gint num_provides_clock ;
190
+ gint num_requires_clock ;
191
+ GHashTable * no_preroll_elements ;
192
+ GHashTable * children_links ;
186
193
};
187
194
188
195
typedef struct
@@ -517,6 +524,9 @@ gst_bin_init (GstBin * bin)
517
524
bin -> priv -> asynchandling = DEFAULT_ASYNC_HANDLING ;
518
525
bin -> priv -> structure_cookie = 0 ;
519
526
bin -> priv -> message_forward = DEFAULT_MESSAGE_FORWARD ;
527
+
528
+ bin -> priv -> no_preroll_elements = g_hash_table_new (NULL , NULL );
529
+ bin -> priv -> children_links = g_hash_table_new (NULL , NULL );
520
530
}
521
531
522
532
static void
@@ -559,6 +569,9 @@ gst_bin_dispose (GObject * object)
559
569
GST_STR_NULL (GST_OBJECT_NAME (object )));
560
570
}
561
571
572
+ g_hash_table_destroy (bin -> priv -> no_preroll_elements );
573
+ g_hash_table_destroy (bin -> priv -> children_links );
574
+
562
575
G_OBJECT_CLASS (parent_class )-> dispose (object );
563
576
}
564
577
@@ -1185,6 +1198,7 @@ gst_bin_do_deep_add_remove (GstBin * bin, gint sig_id, const gchar * sig_name,
1185
1198
static gboolean
1186
1199
gst_bin_add_func (GstBin * bin , GstElement * element )
1187
1200
{
1201
+ GstBinPrivate * priv = bin -> priv ;
1188
1202
gchar * elem_name ;
1189
1203
GstIterator * it ;
1190
1204
GList * walk ;
@@ -1207,18 +1221,18 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
1207
1221
1208
1222
/* Check whether we need to switch to using the hash */
1209
1223
GST_OBJECT_LOCK (bin );
1210
- if ((bin -> priv -> children_hash == NULL ) &&
1211
- (bin -> priv -> numchildren_use_hash >= 0 ) &&
1212
- (bin -> numchildren + 1 ) >= (bin -> priv -> numchildren_use_hash )) {
1224
+ if ((priv -> children_hash == NULL ) &&
1225
+ (priv -> numchildren_use_hash >= 0 ) &&
1226
+ (bin -> numchildren + 1 ) >= (priv -> numchildren_use_hash )) {
1213
1227
/* Time to switch to using the hash */
1214
- bin -> priv -> children_hash = g_hash_table_new_full (g_str_hash , g_str_equal , g_free , NULL );
1228
+ priv -> children_hash = g_hash_table_new_full (g_str_hash , g_str_equal , g_free , NULL );
1215
1229
1216
1230
/* Initialise each existing element into the hash */
1217
1231
walk = bin -> children ;
1218
1232
for (; walk ; walk = g_list_next (walk )) {
1219
1233
GstElement * child ;
1220
1234
child = GST_ELEMENT_CAST (walk -> data );
1221
- g_hash_table_insert (bin -> priv -> children_hash , g_strdup (GST_OBJECT_NAME (child )), child );
1235
+ g_hash_table_insert (priv -> children_hash , g_strdup (GST_OBJECT_NAME (child )), child );
1222
1236
}
1223
1237
}
1224
1238
@@ -1230,10 +1244,10 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
1230
1244
* you can safely change the element name after this check and before setting
1231
1245
* the object parent. The window is very small though... */
1232
1246
1233
- if (bin -> priv -> children_hash != NULL ) {
1247
+ if (priv -> children_hash != NULL ) {
1234
1248
/* Use the hash table to look up whether we already have an element with that
1235
1249
* name */
1236
- if (g_hash_table_contains (bin -> priv -> children_hash , elem_name )) {
1250
+ if (g_hash_table_contains (priv -> children_hash , elem_name )) {
1237
1251
goto duplicate_name ;
1238
1252
}
1239
1253
} else {
@@ -1248,40 +1262,50 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
1248
1262
GST_OBJECT_CAST (bin ))))
1249
1263
goto had_parent ;
1250
1264
1265
+ if (is_sink )
1266
+ priv -> num_is_sink ++ ;
1267
+ if (is_source )
1268
+ priv -> num_is_src ++ ;
1269
+ if (provides_clock )
1270
+ priv -> num_provides_clock ++ ;
1271
+ if (requires_clock )
1272
+ priv -> num_requires_clock ++ ;
1273
+
1251
1274
/* if we add a sink we become a sink */
1252
- if (is_sink && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_SINK )) {
1275
+ if (is_sink && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_SINK )) {
1253
1276
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE , bin , "element \"%s\" was sink" ,
1254
1277
elem_name );
1255
1278
GST_OBJECT_FLAG_SET (bin , GST_ELEMENT_FLAG_SINK );
1256
1279
}
1257
- if (is_source && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_SOURCE )) {
1280
+ if (is_source && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_SOURCE )) {
1258
1281
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE , bin , "element \"%s\" was source" ,
1259
1282
elem_name );
1260
1283
GST_OBJECT_FLAG_SET (bin , GST_ELEMENT_FLAG_SOURCE );
1261
1284
}
1262
1285
if (provides_clock
1263
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_PROVIDE_CLOCK )) {
1286
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_PROVIDE_CLOCK )) {
1264
1287
GST_DEBUG_OBJECT (bin , "element \"%s\" can provide a clock" , elem_name );
1265
1288
clock_message =
1266
1289
gst_message_new_clock_provide (GST_OBJECT_CAST (element ), NULL , TRUE);
1267
1290
GST_OBJECT_FLAG_SET (bin , GST_ELEMENT_FLAG_PROVIDE_CLOCK );
1268
1291
}
1269
1292
if (requires_clock
1270
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_REQUIRE_CLOCK )) {
1293
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_REQUIRE_CLOCK )) {
1271
1294
GST_DEBUG_OBJECT (bin , "element \"%s\" requires a clock" , elem_name );
1272
1295
GST_OBJECT_FLAG_SET (bin , GST_ELEMENT_FLAG_REQUIRE_CLOCK );
1273
1296
}
1274
1297
1275
1298
bin -> children = g_list_prepend (bin -> children , element );
1299
+ g_hash_table_insert (priv -> children_links , element , bin -> children );
1276
1300
1277
- if (bin -> priv -> children_hash != NULL ) {
1278
- g_hash_table_insert (bin -> priv -> children_hash , g_strdup (elem_name ), element );
1301
+ if (priv -> children_hash != NULL ) {
1302
+ g_hash_table_insert (priv -> children_hash , g_strdup (elem_name ), element );
1279
1303
}
1280
1304
1281
1305
bin -> numchildren ++ ;
1282
1306
bin -> children_cookie ++ ;
1283
1307
if (!GST_BIN_IS_NO_RESYNC (bin ))
1284
- bin -> priv -> structure_cookie ++ ;
1308
+ priv -> structure_cookie ++ ;
1285
1309
1286
1310
/* distribute the bus */
1287
1311
gst_element_set_bus (element , bin -> child_bus );
@@ -1352,6 +1376,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
1352
1376
case GST_STATE_CHANGE_NO_PREROLL :
1353
1377
/* ignore all async elements we might have and commit our state */
1354
1378
bin_handle_async_done (bin , ret , FALSE, GST_CLOCK_TIME_NONE );
1379
+ g_hash_table_add (priv -> no_preroll_elements , element );
1355
1380
break ;
1356
1381
case GST_STATE_CHANGE_FAILURE :
1357
1382
break ;
@@ -1611,10 +1636,11 @@ gst_bin_add (GstBin * bin, GstElement * element)
1611
1636
static gboolean
1612
1637
gst_bin_remove_func (GstBin * bin , GstElement * element )
1613
1638
{
1639
+ GstBinPrivate * priv = bin -> priv ;
1614
1640
gchar * elem_name ;
1615
1641
GstIterator * it ;
1616
- gboolean is_sink , is_source , provides_clock , requires_clock ;
1617
- gboolean othersink , othersource , otherprovider , otherrequirer , found ;
1642
+ gboolean is_sink , is_source , provides_clock , requires_clock , no_preroll ;
1643
+ gboolean found ;
1618
1644
GstMessage * clock_message = NULL ;
1619
1645
GstClock * * provided_clock_p ;
1620
1646
GstElement * * clock_provider_p ;
@@ -1644,52 +1670,25 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
1644
1670
GST_OBJECT_FLAG_IS_SET (element , GST_ELEMENT_FLAG_PROVIDE_CLOCK );
1645
1671
requires_clock =
1646
1672
GST_OBJECT_FLAG_IS_SET (element , GST_ELEMENT_FLAG_REQUIRE_CLOCK );
1673
+ no_preroll = GST_STATE_RETURN (element ) == GST_STATE_CHANGE_NO_PREROLL ;
1647
1674
GST_OBJECT_UNLOCK (element );
1648
1675
1676
+ if (!no_preroll )
1677
+ g_hash_table_remove (priv -> no_preroll_elements , element );
1678
+
1649
1679
found = FALSE;
1650
- othersink = FALSE;
1651
- othersource = FALSE;
1652
- otherprovider = FALSE;
1653
- otherrequirer = FALSE;
1654
- have_no_preroll = FALSE;
1680
+ have_no_preroll = g_hash_table_size (priv -> no_preroll_elements ) > 0 ;
1655
1681
/* iterate the elements, we collect which ones are async and no_preroll. We
1656
1682
* also remove the element when we find it. */
1657
- for (walk = bin -> children ; walk ; walk = next ) {
1658
- GstElement * child = GST_ELEMENT_CAST (walk -> data );
1659
-
1660
- next = g_list_next (walk );
1661
1683
1662
- if (child == element ) {
1663
- found = TRUE;
1664
- /* remove the element */
1665
- if (bin -> priv -> children_hash != NULL ) {
1666
- g_hash_table_remove (bin -> priv -> children_hash , elem_name );
1667
- }
1668
- bin -> children = g_list_delete_link (bin -> children , walk );
1669
- } else {
1670
- gboolean child_sink , child_source , child_provider , child_requirer ;
1671
-
1672
- GST_OBJECT_LOCK (child );
1673
- child_sink = GST_OBJECT_FLAG_IS_SET (child , GST_ELEMENT_FLAG_SINK );
1674
- child_source = GST_OBJECT_FLAG_IS_SET (child , GST_ELEMENT_FLAG_SOURCE );
1675
- child_provider =
1676
- GST_OBJECT_FLAG_IS_SET (child , GST_ELEMENT_FLAG_PROVIDE_CLOCK );
1677
- child_requirer =
1678
- GST_OBJECT_FLAG_IS_SET (child , GST_ELEMENT_FLAG_REQUIRE_CLOCK );
1679
- /* when we remove a sink, check if there are other sinks. */
1680
- if (is_sink && !othersink && child_sink )
1681
- othersink = TRUE;
1682
- if (is_source && !othersource && child_source )
1683
- othersource = TRUE;
1684
- if (provides_clock && !otherprovider && child_provider )
1685
- otherprovider = TRUE;
1686
- if (requires_clock && !otherrequirer && child_requirer )
1687
- otherrequirer = TRUE;
1688
- /* check if we have NO_PREROLL children */
1689
- if (GST_STATE_RETURN (child ) == GST_STATE_CHANGE_NO_PREROLL )
1690
- have_no_preroll = TRUE;
1691
- GST_OBJECT_UNLOCK (child );
1684
+ GList * link = g_hash_table_lookup (priv -> children_links , element );
1685
+ if (link ) {
1686
+ if (priv -> children_hash != NULL ) {
1687
+ g_hash_table_remove (priv -> children_hash , elem_name );
1692
1688
}
1689
+ found = TRUE;
1690
+ /* remove the element */
1691
+ bin -> children = g_list_delete_link (bin -> children , link );
1693
1692
}
1694
1693
1695
1694
/* the element must have been in the bin's list of children */
@@ -1701,28 +1700,37 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
1701
1700
bin -> numchildren -- ;
1702
1701
bin -> children_cookie ++ ;
1703
1702
if (!GST_BIN_IS_NO_RESYNC (bin ))
1704
- bin -> priv -> structure_cookie ++ ;
1705
-
1706
- if (is_sink && !othersink
1707
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_SINK )) {
1703
+ priv -> structure_cookie ++ ;
1704
+
1705
+ if (is_sink )
1706
+ priv -> num_is_sink -- ;
1707
+ if (is_source )
1708
+ priv -> num_is_src -- ;
1709
+ if (provides_clock )
1710
+ priv -> num_provides_clock -- ;
1711
+ if (requires_clock )
1712
+ priv -> num_requires_clock -- ;
1713
+
1714
+ if (priv -> num_is_sink == 0
1715
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_SINK )) {
1708
1716
/* we're not a sink anymore */
1709
1717
GST_DEBUG_OBJECT (bin , "we removed the last sink" );
1710
1718
GST_OBJECT_FLAG_UNSET (bin , GST_ELEMENT_FLAG_SINK );
1711
1719
}
1712
- if (is_source && ! othersource
1713
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_SOURCE )) {
1720
+ if (priv -> num_is_src == 0
1721
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_SOURCE )) {
1714
1722
/* we're not a source anymore */
1715
1723
GST_DEBUG_OBJECT (bin , "we removed the last source" );
1716
1724
GST_OBJECT_FLAG_UNSET (bin , GST_ELEMENT_FLAG_SOURCE );
1717
1725
}
1718
- if (provides_clock && ! otherprovider
1719
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_PROVIDE_CLOCK )) {
1726
+ if (priv -> num_provides_clock == 0
1727
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_PROVIDE_CLOCK )) {
1720
1728
/* we're not a clock provider anymore */
1721
1729
GST_DEBUG_OBJECT (bin , "we removed the last clock provider" );
1722
1730
GST_OBJECT_FLAG_UNSET (bin , GST_ELEMENT_FLAG_PROVIDE_CLOCK );
1723
1731
}
1724
- if (requires_clock && ! otherrequirer
1725
- && !(bin -> priv -> suppressed_flags & GST_ELEMENT_FLAG_REQUIRE_CLOCK )) {
1732
+ if (priv -> num_requires_clock == 0
1733
+ && !(priv -> suppressed_flags & GST_ELEMENT_FLAG_REQUIRE_CLOCK )) {
1726
1734
/* we're not a clock requirer anymore */
1727
1735
GST_DEBUG_OBJECT (bin , "we removed the last clock requirer" );
1728
1736
GST_OBJECT_FLAG_UNSET (bin , GST_ELEMENT_FLAG_REQUIRE_CLOCK );
@@ -2539,9 +2547,12 @@ gst_bin_element_set_state (GstBin * bin, GstElement * element,
2539
2547
* anyway. */
2540
2548
if (G_UNLIKELY (ret == GST_STATE_CHANGE_NO_PREROLL )) {
2541
2549
GST_DEBUG_OBJECT (element , "element is NO_PREROLL, ignore async elements" );
2550
+ g_hash_table_add (bin -> priv -> no_preroll_elements , element );
2542
2551
goto no_preroll ;
2543
2552
}
2544
2553
2554
+ g_hash_table_remove (bin -> priv -> no_preroll_elements , element );
2555
+
2545
2556
GST_CAT_INFO_OBJECT (GST_CAT_STATES , element ,
2546
2557
"current %s pending %s, desired next %s" ,
2547
2558
gst_element_state_get_name (child_current ),
0 commit comments