From dbd694c7c400c102084f2cbec321a664bae42c76 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Wed, 23 Nov 2011 16:09:13 +0000 Subject: [PATCH 01/18] vorbisenc: do not accept 256 channels, 255 is the max vorbis supports --- ext/vorbis/gstvorbisenc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/vorbis/gstvorbisenc.c b/ext/vorbis/gstvorbisenc.c index 56653178b7..45c871a085 100644 --- a/ext/vorbis/gstvorbisenc.c +++ b/ext/vorbis/gstvorbisenc.c @@ -65,7 +65,7 @@ GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-float, " "rate = (int) [ 1, 200000 ], " - "channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, " + "channels = (int) [ 1, 255 ], " "endianness = (int) BYTE_ORDER, " "width = (int) 32") ); @@ -310,7 +310,7 @@ gst_vorbis_enc_generate_sink_caps (void) gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", "rate", GST_TYPE_INT_RANGE, 1, 200000, - "channels", GST_TYPE_INT_RANGE, 9, 256, + "channels", GST_TYPE_INT_RANGE, 9, 255, "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL)); From db21375406f00db1e0791050f1b0bf576f4efd5d Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Fri, 21 Oct 2011 19:38:19 +0100 Subject: [PATCH 02/18] oggdemux: gather some more stats about bisection https://bugzilla.gnome.org/show_bug.cgi?id=662475 --- ext/ogg/gstoggdemux.c | 19 +++++++++++++++++++ ext/ogg/gstoggdemux.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 2426b7275f..4198f6cbdc 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -1440,6 +1440,19 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) } GST_INFO_OBJECT (ogg, "Bisection needed %d + %d steps", ogg->push_bisection_steps[0], ogg->push_bisection_steps[1]); + ogg->stats_bisection_steps[0] += ogg->push_bisection_steps[0]; + ogg->stats_bisection_steps[1] += ogg->push_bisection_steps[1]; + if (ogg->stats_bisection_max_steps[0] < ogg->push_bisection_steps[0]) + ogg->stats_bisection_max_steps[0] = ogg->push_bisection_steps[0]; + if (ogg->stats_bisection_max_steps[1] < ogg->push_bisection_steps[1]) + ogg->stats_bisection_max_steps[1] = ogg->push_bisection_steps[1]; + ogg->stats_nbisections++; + GST_INFO_OBJECT (ogg, + "So far, %.2f + %.2f bisections needed per seek (max %d + %d)", + ogg->stats_bisection_steps[0] / (float) ogg->stats_nbisections, + ogg->stats_bisection_steps[1] / (float) ogg->stats_nbisections, + ogg->stats_bisection_max_steps[0], + ogg->stats_bisection_max_steps[1]); } } } else if (ogg->push_state == PUSH_LINEAR1) { @@ -1853,6 +1866,12 @@ gst_ogg_demux_init (GstOggDemux * ogg, GstOggDemuxClass * g_class) ogg->push_lock = g_mutex_new (); ogg->chains = g_array_new (FALSE, TRUE, sizeof (GstOggChain *)); + ogg->stats_nbisections = 0; + ogg->stats_bisection_steps[0] = 0; + ogg->stats_bisection_steps[1] = 0; + ogg->stats_bisection_max_steps[0] = 0; + ogg->stats_bisection_max_steps[1] = 0; + ogg->newsegment = NULL; } diff --git a/ext/ogg/gstoggdemux.h b/ext/ogg/gstoggdemux.h index 712dc8f05c..fea4c60dc5 100644 --- a/ext/ogg/gstoggdemux.h +++ b/ext/ogg/gstoggdemux.h @@ -188,6 +188,9 @@ struct _GstOggDemux gboolean push_disable_seeking; gint push_bisection_steps[2]; + gint stats_bisection_steps[2]; + gint stats_bisection_max_steps[2]; + gint stats_nbisections; /* ogg stuff */ ogg_sync_state sync; From e7079cd8d5a7752f8052a093ca694f9e5a070fb0 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Sat, 22 Oct 2011 20:20:38 +0100 Subject: [PATCH 03/18] oggdemux: improve push time seeking Various tweaks to improve convergence, in particular for the worst case, which is now cut in about half. https://bugzilla.gnome.org/show_bug.cgi?id=662475 --- ext/ogg/gstoggdemux.c | 149 ++++++++++++++++++++++++++++++++++++------ ext/ogg/gstoggdemux.h | 7 ++ 2 files changed, 136 insertions(+), 20 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 4198f6cbdc..3afbd91976 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -1066,6 +1066,8 @@ gst_ogg_pad_stream_out (GstOggPad * pad, gint npackets) break; case 1: GST_LOG_OBJECT (ogg, "packetout gave packet of size %ld", packet.bytes); + if (packet.bytes > ogg->max_packet_size) + ogg->max_packet_size = packet.bytes; result = gst_ogg_pad_submit_packet (pad, &packet); /* not linked is not a problem, it's possible that we are still * collecting headers and that we don't have exposed the pads yet */ @@ -1107,19 +1109,22 @@ gst_ogg_demux_setup_bisection_bounds (GstOggDemux * ogg) GST_TIME_ARGS (ogg->push_last_seek_time - ogg->push_seek_time_target)); ogg->push_offset1 = ogg->push_last_seek_offset; ogg->push_time1 = ogg->push_last_seek_time; + ogg->seek_undershot = FALSE; } else { GST_DEBUG_OBJECT (ogg, "We undershot by %" GST_TIME_FORMAT, GST_TIME_ARGS (ogg->push_seek_time_target - ogg->push_last_seek_time)); ogg->push_offset0 = ogg->push_last_seek_offset; ogg->push_time0 = ogg->push_last_seek_time; + ogg->seek_undershot = TRUE; } } static gint64 -gst_ogg_demux_estimate_bisection_target (GstOggDemux * ogg) +gst_ogg_demux_estimate_bisection_target (GstOggDemux * ogg, float seek_quality) { gint64 best; gint64 segment_bitrate; + gint64 skew; /* we might not know the length of the stream in time, so push_time1 might not be set */ @@ -1146,6 +1151,7 @@ gst_ogg_demux_estimate_bisection_target (GstOggDemux * ogg) ogg->push_offset0 + gst_util_uint64_scale (ogg->push_seek_time_target - ogg->push_time0, segment_bitrate, 8 * GST_SECOND); + ogg->seek_secant = TRUE; } else { GST_DEBUG_OBJECT (ogg, "New segment to consider: bytes %" G_GINT64_FORMAT " %" G_GINT64_FORMAT @@ -1162,20 +1168,63 @@ gst_ogg_demux_estimate_bisection_target (GstOggDemux * ogg) "Local bitrate on the %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT " segment: %" G_GINT64_FORMAT, GST_TIME_ARGS (ogg->push_time0), GST_TIME_ARGS (ogg->push_time1), segment_bitrate); + best = ogg->push_offset0 + gst_util_uint64_scale (ogg->push_seek_time_target - ogg->push_time0, segment_bitrate, 8 * GST_SECOND); + if (seek_quality < 0.5f && ogg->seek_secant) { + gint64 new_best, best2 = (ogg->push_offset0 + ogg->push_offset1) / 2; + /* if dire result, give as much as 25% weight to a dumb bisection guess */ + float secant_weight = 1.0f - ((0.5 - seek_quality) / 0.5f) * 0.25; + new_best = (best * secant_weight + best2 * (1.0f - secant_weight)); + GST_DEBUG_OBJECT (ogg, + "Secant says %" G_GINT64_FORMAT ", straight is %" G_GINT64_FORMAT + ", new best %" G_GINT64_FORMAT " with secant_weight %f", best, + best2, new_best, secant_weight); + best = new_best; + ogg->seek_secant = FALSE; + } else { + ogg->seek_secant = TRUE; + } } } - /* offset by typical page size */ - best -= CHUNKSIZE; + GST_DEBUG_OBJECT (ogg, "Raw best guess: %" G_GINT64_FORMAT, best); + + /* offset the guess down as we need to capture the start of the + page we are targetting - but only do so if we did not undershoot + last time, as we're likely to still do this time */ + if (!ogg->seek_undershot) { + /* very small packets are packed on pages, so offset by at least + a value which is likely to get us at least one page where the + packet starts */ + skew = + ogg->max_packet_size > + ogg->max_page_size ? ogg->max_packet_size : ogg->max_page_size; + GST_DEBUG_OBJECT (ogg, "Offsetting by %" G_GINT64_FORMAT, skew); + best -= skew; + } + + /* do not seek too close to the bounds, as we stop seeking + when we get to within max_packet_size before the target */ + if (best > ogg->push_offset1 - ogg->max_packet_size) { + best = ogg->push_offset1 - ogg->max_packet_size; + GST_DEBUG_OBJECT (ogg, + "Too close to high bound, pushing back to %" G_GINT64_FORMAT, best); + } else if (best < ogg->push_offset0 + ogg->max_packet_size) { + best = ogg->push_offset0 + ogg->max_packet_size; + GST_DEBUG_OBJECT (ogg, + "Too close to low bound, pushing forth to %" G_GINT64_FORMAT, best); + } + + /* keep within bounds */ + if (best > ogg->push_offset1) + best = ogg->push_offset1; if (best < ogg->push_offset0) best = ogg->push_offset0; - if (best < 0) - best = 0; + GST_DEBUG_OBJECT (ogg, "Choosing target %" G_GINT64_FORMAT, best); return best; } @@ -1252,6 +1301,38 @@ gst_ogg_demux_seek_back_after_push_duration_check_unlock (GstOggDemux * ogg) return GST_FLOW_OK; } +static float +gst_ogg_demux_estimate_seek_quality (GstOggDemux * ogg) +{ + gint64 diff; /* how far from the goal we ended up */ + gint64 dist; /* how far we moved this iteration */ + float seek_quality; + + if (ogg->push_prev_seek_time == GST_CLOCK_TIME_NONE) { + /* for the first seek, we pretend we got a good seek, + as we don't have a previous seek yet */ + return 1.0f; + } + + /* We take a guess at how good the last seek was at guessing + the byte target by comparing the amplitude of the last + seek to the error */ + diff = ogg->push_seek_time_target - ogg->push_last_seek_time; + if (diff < 0) + diff = -diff; + dist = ogg->push_last_seek_time - ogg->push_prev_seek_time; + if (dist < 0) + dist = -dist; + + seek_quality = (dist == 0) ? 0.0f : 1.0f / (1.0f + diff / (float) dist); + + GST_DEBUG_OBJECT (ogg, + "We moved %" GST_TIME_FORMAT ", we're off by %" GST_TIME_FORMAT + ", seek quality %f", GST_TIME_ARGS (dist), GST_TIME_ARGS (diff), + seek_quality); + return seek_quality; +} + static gboolean gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) { @@ -1327,6 +1408,7 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) GstEvent *sevent; int res; gboolean close_enough; + float seek_quality; /* ignore -1 granpos when seeking, we want to sync on a real granpos */ if (granpos < 0) { @@ -1364,14 +1446,18 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) GST_TIME_ARGS (ogg->push_seek_time_target)); if (ogg->push_time1 != GST_CLOCK_TIME_NONE) { + seek_quality = gst_ogg_demux_estimate_seek_quality (ogg); GST_DEBUG_OBJECT (ogg, "Interval was %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%" G_GINT64_FORMAT "), time %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT - " (%" GST_TIME_FORMAT ")", ogg->push_offset0, ogg->push_offset1, - ogg->push_offset1 - ogg->push_offset0, + " (%" GST_TIME_FORMAT "), seek quality %f", ogg->push_offset0, + ogg->push_offset1, ogg->push_offset1 - ogg->push_offset0, GST_TIME_ARGS (ogg->push_time0), GST_TIME_ARGS (ogg->push_time1), - GST_TIME_ARGS (ogg->push_time1 - ogg->push_time0)); + GST_TIME_ARGS (ogg->push_time1 - ogg->push_time0), seek_quality); } else { + /* in a open ended seek, we can't do bisection, so we pretend + we like our result so far */ + seek_quality = 1.0f; GST_DEBUG_OBJECT (ogg, "Interval was %" G_GINT64_FORMAT " - %" G_GINT64_FORMAT " (%" G_GINT64_FORMAT "), time %" GST_TIME_FORMAT " - unknown", @@ -1379,30 +1465,39 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) ogg->push_offset1 - ogg->push_offset0, GST_TIME_ARGS (ogg->push_time0)); } + ogg->push_prev_seek_time = ogg->push_last_seek_time; gst_ogg_demux_setup_bisection_bounds (ogg); - best = gst_ogg_demux_estimate_bisection_target (ogg); + best = gst_ogg_demux_estimate_bisection_target (ogg, seek_quality); if (ogg->push_seek_time_target == 0) { GST_DEBUG_OBJECT (ogg, "Seeking to 0, deemed close enough"); close_enough = (ogg->push_last_seek_time == 0); } else { /* TODO: make this dependent on framerate ? */ - GstClockTime threshold = GST_SECOND / 2; + GstClockTime time_threshold = GST_SECOND / 2; + guint64 byte_threshold = + (ogg->max_packet_size > + 64 * 1024 ? ogg->max_packet_size : 64 * 1024); - /* We want to be within half a second before the target */ - if (threshold > ogg->push_seek_time_target) - threshold = ogg->push_seek_time_target; + /* We want to be within half a second before the target, + or before the target and half less or equal to the max + packet size left to search in */ + if (time_threshold > ogg->push_seek_time_target) + time_threshold = ogg->push_seek_time_target; close_enough = ogg->push_last_seek_time < ogg->push_seek_time_target - && ogg->push_last_seek_time >= - ogg->push_seek_time_target - threshold; + && (ogg->push_last_seek_time >= + ogg->push_seek_time_target - time_threshold + || ogg->push_offset1 <= ogg->push_offset0 + byte_threshold); GST_DEBUG_OBJECT (ogg, "testing if we're close enough: %" GST_TIME_FORMAT " <= %" - GST_TIME_FORMAT " < %" GST_TIME_FORMAT " ? %s", - GST_TIME_ARGS (ogg->push_seek_time_target - threshold), + GST_TIME_FORMAT " < %" GST_TIME_FORMAT ", or %" G_GUINT64_FORMAT + " <= %" G_GUINT64_FORMAT " ? %s", + GST_TIME_ARGS (ogg->push_seek_time_target - time_threshold), GST_TIME_ARGS (ogg->push_last_seek_time), GST_TIME_ARGS (ogg->push_seek_time_target), + ogg->push_offset1 - ogg->push_offset0, byte_threshold, close_enough ? "Yes" : "No"); } @@ -1432,7 +1527,7 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) GST_TIME_ARGS (ogg->push_seek_time_original_target)); ogg->push_state = PUSH_LINEAR2; } else { - GST_DEBUG_OBJECT (ogg, "Seek to keyframe done, playing"); + GST_INFO_OBJECT (ogg, "Seek to keyframe done, playing"); /* we're synced to the seek target, so flush stream and stuff any queued pages into the stream so we start decoding there */ @@ -1466,14 +1561,22 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) GST_TIME_ARGS (pad->push_kf_time)); earliest_keyframe_time = gst_ogg_demux_get_earliest_keyframe_time (ogg); if (earliest_keyframe_time != GST_CLOCK_TIME_NONE) { - GST_DEBUG_OBJECT (ogg, + GST_INFO_OBJECT (ogg, "All non sparse streams now have a previous keyframe time," "bisecting again to %" GST_TIME_FORMAT, GST_TIME_ARGS (earliest_keyframe_time)); + ogg->push_seek_time_target = earliest_keyframe_time; + ogg->push_offset0 = 0; + ogg->push_time0 = ogg->push_start_time; + ogg->push_offset1 = ogg->push_last_seek_offset; + ogg->push_time1 = ogg->push_last_seek_time; + ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE; + ogg->seek_secant = FALSE; + ogg->seek_undershot = FALSE; ogg->push_state = PUSH_BISECT2; - best = gst_ogg_demux_estimate_bisection_target (ogg); + best = gst_ogg_demux_estimate_bisection_target (ogg, 1.0f); } } } @@ -1578,6 +1681,9 @@ gst_ogg_pad_submit_page (GstOggPad * pad, ogg_page * page) return result; } + if (page->header_len + page->body_len > ogg->max_page_size) + ogg->max_page_size = page->header_len + page->body_len; + if (ogg_stream_pagein (&pad->map.stream, page) != 0) goto choked; @@ -3289,8 +3395,11 @@ gst_ogg_demux_perform_seek_push (GstOggDemux * ogg, GstEvent * event) ogg->push_time0 = ogg->push_start_time; ogg->push_time1 = ogg->push_time_length; ogg->push_seek_time_target = start; + ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE; ogg->push_seek_time_original_target = start; ogg->push_state = PUSH_BISECT1; + ogg->seek_secant = FALSE; + ogg->seek_undershot = FALSE; /* reset pad push mode seeking state */ for (i = 0; i < chain->streams->len; i++) { diff --git a/ext/ogg/gstoggdemux.h b/ext/ogg/gstoggdemux.h index fea4c60dc5..a8ac92b463 100644 --- a/ext/ogg/gstoggdemux.h +++ b/ext/ogg/gstoggdemux.h @@ -145,6 +145,10 @@ struct _GstOggDemux gboolean need_chains; gboolean resync; + /* keep track of how large pages and packets are, + useful for skewing when seeking */ + guint64 max_packet_size, max_page_size; + /* state */ GMutex *chain_lock; /* we need the lock to protect the chains */ GArray *chains; /* list of chains we know */ @@ -186,6 +190,9 @@ struct _GstOggDemux GstSeekFlags push_seek_flags; GstEvent *push_mode_seek_delayed_event; gboolean push_disable_seeking; + gboolean seek_secant; + gboolean seek_undershot; + GstClockTime push_prev_seek_time; gint push_bisection_steps[2]; gint stats_bisection_steps[2]; From b0bb1d353925c935d93f37706f21d8b199505ec5 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Sat, 22 Oct 2011 20:29:26 +0100 Subject: [PATCH 04/18] oggdemux: skip the second bisection when possible If we already saw the keyframes that we need to find, we do not need to bisect to find them. This will always be the case for streams with audio only, where each frame acts as a keyframe, but will occasionally also happen for streams with video. https://bugzilla.gnome.org/show_bug.cgi?id=662475 --- ext/ogg/gstoggdemux.c | 71 +++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 3afbd91976..16bcf6c23e 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -1333,6 +1333,25 @@ gst_ogg_demux_estimate_seek_quality (GstOggDemux * ogg) return seek_quality; } +static void +gst_ogg_demux_update_bisection_stats (GstOggDemux * ogg) +{ + GST_INFO_OBJECT (ogg, "Bisection needed %d + %d steps", + ogg->push_bisection_steps[0], ogg->push_bisection_steps[1]); + ogg->stats_bisection_steps[0] += ogg->push_bisection_steps[0]; + ogg->stats_bisection_steps[1] += ogg->push_bisection_steps[1]; + if (ogg->stats_bisection_max_steps[0] < ogg->push_bisection_steps[0]) + ogg->stats_bisection_max_steps[0] = ogg->push_bisection_steps[0]; + if (ogg->stats_bisection_max_steps[1] < ogg->push_bisection_steps[1]) + ogg->stats_bisection_max_steps[1] = ogg->push_bisection_steps[1]; + ogg->stats_nbisections++; + GST_INFO_OBJECT (ogg, + "So far, %.2f + %.2f bisections needed per seek (max %d + %d)", + ogg->stats_bisection_steps[0] / (float) ogg->stats_nbisections, + ogg->stats_bisection_steps[1] / (float) ogg->stats_nbisections, + ogg->stats_bisection_max_steps[0], ogg->stats_bisection_max_steps[1]); +} + static gboolean gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) { @@ -1533,21 +1552,7 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) any queued pages into the stream so we start decoding there */ ogg->push_state = PUSH_PLAYING; } - GST_INFO_OBJECT (ogg, "Bisection needed %d + %d steps", - ogg->push_bisection_steps[0], ogg->push_bisection_steps[1]); - ogg->stats_bisection_steps[0] += ogg->push_bisection_steps[0]; - ogg->stats_bisection_steps[1] += ogg->push_bisection_steps[1]; - if (ogg->stats_bisection_max_steps[0] < ogg->push_bisection_steps[0]) - ogg->stats_bisection_max_steps[0] = ogg->push_bisection_steps[0]; - if (ogg->stats_bisection_max_steps[1] < ogg->push_bisection_steps[1]) - ogg->stats_bisection_max_steps[1] = ogg->push_bisection_steps[1]; - ogg->stats_nbisections++; - GST_INFO_OBJECT (ogg, - "So far, %.2f + %.2f bisections needed per seek (max %d + %d)", - ogg->stats_bisection_steps[0] / (float) ogg->stats_nbisections, - ogg->stats_bisection_steps[1] / (float) ogg->stats_nbisections, - ogg->stats_bisection_max_steps[0], - ogg->stats_bisection_max_steps[1]); + gst_ogg_demux_update_bisection_stats (ogg); } } } else if (ogg->push_state == PUSH_LINEAR1) { @@ -1561,22 +1566,30 @@ gst_ogg_pad_handle_push_mode_state (GstOggPad * pad, ogg_page * page) GST_TIME_ARGS (pad->push_kf_time)); earliest_keyframe_time = gst_ogg_demux_get_earliest_keyframe_time (ogg); if (earliest_keyframe_time != GST_CLOCK_TIME_NONE) { - GST_INFO_OBJECT (ogg, - "All non sparse streams now have a previous keyframe time," - "bisecting again to %" GST_TIME_FORMAT, - GST_TIME_ARGS (earliest_keyframe_time)); + if (earliest_keyframe_time > ogg->push_last_seek_time) { + GST_INFO_OBJECT (ogg, + "All non sparse streams now have a previous keyframe time, " + "and we already decoded it, switching to playing"); + ogg->push_state = PUSH_PLAYING; + gst_ogg_demux_update_bisection_stats (ogg); + } else { + GST_INFO_OBJECT (ogg, + "All non sparse streams now have a previous keyframe time, " + "bisecting again to %" GST_TIME_FORMAT, + GST_TIME_ARGS (earliest_keyframe_time)); - ogg->push_seek_time_target = earliest_keyframe_time; - ogg->push_offset0 = 0; - ogg->push_time0 = ogg->push_start_time; - ogg->push_offset1 = ogg->push_last_seek_offset; - ogg->push_time1 = ogg->push_last_seek_time; - ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE; - ogg->seek_secant = FALSE; - ogg->seek_undershot = FALSE; + ogg->push_seek_time_target = earliest_keyframe_time; + ogg->push_offset0 = 0; + ogg->push_time0 = ogg->push_start_time; + ogg->push_offset1 = ogg->push_last_seek_offset; + ogg->push_time1 = ogg->push_last_seek_time; + ogg->push_prev_seek_time = GST_CLOCK_TIME_NONE; + ogg->seek_secant = FALSE; + ogg->seek_undershot = FALSE; - ogg->push_state = PUSH_BISECT2; - best = gst_ogg_demux_estimate_bisection_target (ogg, 1.0f); + ogg->push_state = PUSH_BISECT2; + best = gst_ogg_demux_estimate_bisection_target (ogg, 1.0f); + } } } } From 8f165b6206c997d6b7be0aae6be41901b0fb4e74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 11:34:12 +0100 Subject: [PATCH 05/18] playsinkaudioconvert: use-volume and use-converters are no construct-only properties anymore Fixes bug #663893. --- gst/playback/gstplaysinkaudioconvert.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gst/playback/gstplaysinkaudioconvert.c b/gst/playback/gstplaysinkaudioconvert.c index f8783d067b..a0756bc476 100644 --- a/gst/playback/gstplaysinkaudioconvert.c +++ b/gst/playback/gstplaysinkaudioconvert.c @@ -179,12 +179,12 @@ gst_play_sink_audio_convert_class_init (GstPlaySinkAudioConvertClass * klass) g_object_class_install_property (gobject_class, PROP_USE_CONVERTERS, g_param_spec_boolean ("use-converters", "Use converters", "Whether to use conversion elements", FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_USE_VOLUME, g_param_spec_boolean ("use-volume", "Use volume", "Whether to use a volume element", FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); gst_element_class_set_details_simple (gstelement_class, "Player Sink Audio Converter", "Audio/Bin/Converter", From 113546b777ed24c785698b0ec09a385224eb745a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 12:37:58 +0100 Subject: [PATCH 06/18] playsinkconvertbin: Override acceptcaps function for the two ghostpads The ghostpad acceptcaps functions are not valid in this case because we don't only accept the caps accepted by the target but could also insert converters. Fixes bug #663892. --- gst/playback/gstplaysinkconvertbin.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gst/playback/gstplaysinkconvertbin.c b/gst/playback/gstplaysinkconvertbin.c index 99a2e380bb..50b1d6d3de 100644 --- a/gst/playback/gstplaysinkconvertbin.c +++ b/gst/playback/gstplaysinkconvertbin.c @@ -394,6 +394,22 @@ gst_play_sink_convert_bin_getcaps (GstPad * pad) gst_object_unref (self); + GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, ret); + + return ret; +} + +static gboolean +gst_play_sink_convert_bin_acceptcaps (GstPad * pad, GstCaps * caps) +{ + GstCaps *allowed_caps; + gboolean ret; + + allowed_caps = gst_pad_get_caps_reffed (pad); + /* FIXME 0.11: Should be a subset check now */ + ret = gst_caps_can_intersect (caps, allowed_caps); + gst_caps_unref (allowed_caps); + return ret; } @@ -561,6 +577,8 @@ gst_play_sink_convert_bin_init (GstPlaySinkConvertBin * self) GST_DEBUG_FUNCPTR (gst_play_sink_convert_bin_sink_setcaps)); gst_pad_set_getcaps_function (self->sinkpad, GST_DEBUG_FUNCPTR (gst_play_sink_convert_bin_getcaps)); + gst_pad_set_acceptcaps_function (self->sinkpad, + GST_DEBUG_FUNCPTR (gst_play_sink_convert_bin_acceptcaps)); self->sink_proxypad = GST_PAD_CAST (gst_proxy_pad_get_internal (GST_PROXY_PAD (self->sinkpad))); @@ -572,6 +590,8 @@ gst_play_sink_convert_bin_init (GstPlaySinkConvertBin * self) self->srcpad = gst_ghost_pad_new_no_target_from_template ("src", templ); gst_pad_set_getcaps_function (self->srcpad, GST_DEBUG_FUNCPTR (gst_play_sink_convert_bin_getcaps)); + gst_pad_set_acceptcaps_function (self->srcpad, + GST_DEBUG_FUNCPTR (gst_play_sink_convert_bin_acceptcaps)); gst_element_add_pad (GST_ELEMENT_CAST (self), self->srcpad); gst_object_unref (templ); From 683735a01e077e4f8082dd9a87664544058a3cf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 12:38:54 +0100 Subject: [PATCH 07/18] playsinkconvertbin: Reconfigure if we switch from raw to incompatible raw caps We might need to add converters and worked in passthrough mode before. --- gst/playback/gstplaysinkconvertbin.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/gst/playback/gstplaysinkconvertbin.c b/gst/playback/gstplaysinkconvertbin.c index 50b1d6d3de..d49224d58b 100644 --- a/gst/playback/gstplaysinkconvertbin.c +++ b/gst/playback/gstplaysinkconvertbin.c @@ -319,13 +319,25 @@ gst_play_sink_convert_bin_sink_setcaps (GstPad * pad, GstCaps * caps) GST_DEBUG_OBJECT (self, "raw %d, self->raw %d, blocked %d", raw, self->raw, gst_pad_is_blocked (self->sink_proxypad)); + if (raw) { - if (!self->raw && !gst_pad_is_blocked (self->sink_proxypad)) { - GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw"); - reconfigure = TRUE; - gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE, - (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), - (GDestroyNotify) gst_object_unref); + if (!gst_pad_is_blocked (self->sink_proxypad)) { + GstPad *target = gst_ghost_pad_get_target (GST_GHOST_PAD (self->sinkpad)); + + if (!self->raw || (target && !gst_pad_accept_caps (target, caps))) { + if (!self->raw) + GST_DEBUG_OBJECT (self, "Changing caps from non-raw to raw"); + else + GST_DEBUG_OBJECT (self, "Changing caps in an incompatible way"); + + reconfigure = TRUE; + gst_pad_set_blocked_async_full (self->sink_proxypad, TRUE, + (GstPadBlockCallback) pad_blocked_cb, gst_object_ref (self), + (GDestroyNotify) gst_object_unref); + } + + if (target) + gst_object_unref (target); } } else { if (self->raw && !gst_pad_is_blocked (self->sink_proxypad)) { From ec062ef3f2a6feb87e431430e88e55a54f62a1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 14:29:49 +0100 Subject: [PATCH 08/18] videorate: Add property to force an output framerate API: GstVideoRate:force-fps Changing the framerate during playback is not possible with a capsfilter downstream if upstream is not using gst_pad_alloc_buffer(). In that case there's no way in 0.10 to signal to videorate that the preferred framerate has changed. This new property will force the output framerate to a specific value and can be changed during playback. --- gst/videorate/gstvideorate.c | 40 ++++++++++++++++++++++++++++++++++-- gst/videorate/gstvideorate.h | 1 + 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index 667dac87ed..05d4adbf84 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -89,6 +89,8 @@ enum #define DEFAULT_DROP_ONLY FALSE #define DEFAULT_AVERAGE_PERIOD 0 #define DEFAULT_MAX_RATE G_MAXINT +#define DEFAULT_FORCE_FPS_N -1 +#define DEFAULT_FORCE_FPS_D 1 enum { @@ -102,7 +104,8 @@ enum ARG_SKIP_TO_FIRST, ARG_DROP_ONLY, ARG_AVERAGE_PERIOD, - ARG_MAX_RATE + ARG_MAX_RATE, + ARG_FORCE_FPS /* FILL ME */ }; @@ -270,6 +273,19 @@ gst_video_rate_class_init (GstVideoRateClass * klass) "(in frames per second, implies drop-only)", 1, G_MAXINT, DEFAULT_MAX_RATE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + /** + * GstVideoRate:force-fps: + * + * Forced output framerate + * + * Since: 0.10.36 + */ + g_object_class_install_property (object_class, ARG_FORCE_FPS, + gst_param_spec_fraction ("force-fps", "Force output framerate", + "Force output framerate (negative means negotiate via caps)", + -1, 1, G_MAXINT, 1, DEFAULT_FORCE_FPS_N, DEFAULT_FORCE_FPS_D, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); } static void @@ -389,7 +405,16 @@ gst_video_rate_transform_caps (GstBaseTransform * trans, s = gst_caps_get_structure (ret, 0); s2 = gst_structure_copy (s); - if (videorate->drop_only) { + if (videorate->force_fps_n >= 0 && videorate->force_fps_d >= 0) { + if (direction == GST_PAD_SINK) { + gst_caps_remove_structure (ret, 0); + gst_structure_set (s2, "framerate", GST_TYPE_FRACTION, + videorate->force_fps_n, videorate->force_fps_d, NULL); + } else { + gst_structure_set (s2, "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, + G_MAXINT, 1, NULL); + } + } else if (videorate->drop_only) { gint min_num = 0, min_denom = 1; gint max_num = G_MAXINT, max_denom = 1; @@ -563,6 +588,8 @@ gst_video_rate_init (GstVideoRate * videorate, GstVideoRateClass * klass) videorate->average_period = DEFAULT_AVERAGE_PERIOD; videorate->average_period_set = DEFAULT_AVERAGE_PERIOD; videorate->max_rate = DEFAULT_MAX_RATE; + videorate->force_fps_n = DEFAULT_FORCE_FPS_N; + videorate->force_fps_d = DEFAULT_FORCE_FPS_D; videorate->from_rate_numerator = 0; videorate->from_rate_denominator = 0; @@ -1176,6 +1203,11 @@ gst_video_rate_set_property (GObject * object, g_atomic_int_set (&videorate->max_rate, g_value_get_int (value)); goto reconfigure; break; + case ARG_FORCE_FPS: + videorate->force_fps_n = gst_value_get_fraction_numerator (value); + videorate->force_fps_d = gst_value_get_fraction_denominator (value); + goto reconfigure; + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1226,6 +1258,10 @@ gst_video_rate_get_property (GObject * object, case ARG_MAX_RATE: g_value_set_int (value, g_atomic_int_get (&videorate->max_rate)); break; + case ARG_FORCE_FPS: + gst_value_set_fraction (value, videorate->force_fps_n, + videorate->force_fps_d); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h index 998d6daa9a..772548c9e7 100644 --- a/gst/videorate/gstvideorate.h +++ b/gst/videorate/gstvideorate.h @@ -76,6 +76,7 @@ struct _GstVideoRate gboolean skip_to_first; gboolean drop_only; guint64 average_period_set; + gint force_fps_n, force_fps_d; volatile int max_rate; }; From c6cffcfa19df25b0e18199dc1ebce69f7e456515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 24 Nov 2011 14:41:13 +0100 Subject: [PATCH 09/18] videorate: Rename ARG_ enums to PROP_ This is more consistent with other code and these are properties anyway, not arguments --- gst/videorate/gstvideorate.c | 82 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c index 05d4adbf84..bf416fa000 100644 --- a/gst/videorate/gstvideorate.c +++ b/gst/videorate/gstvideorate.c @@ -94,18 +94,18 @@ enum enum { - ARG_0, - ARG_IN, - ARG_OUT, - ARG_DUP, - ARG_DROP, - ARG_SILENT, - ARG_NEW_PREF, - ARG_SKIP_TO_FIRST, - ARG_DROP_ONLY, - ARG_AVERAGE_PERIOD, - ARG_MAX_RATE, - ARG_FORCE_FPS + PROP_0, + PROP_IN, + PROP_OUT, + PROP_DUP, + PROP_DROP, + PROP_SILENT, + PROP_NEW_PREF, + PROP_SKIP_TO_FIRST, + PROP_DROP_ONLY, + PROP_AVERAGE_PERIOD, + PROP_MAX_RATE, + PROP_FORCE_FPS /* FILL ME */ }; @@ -198,25 +198,25 @@ gst_video_rate_class_init (GstVideoRateClass * klass) base_class->fixate_caps = GST_DEBUG_FUNCPTR (gst_video_rate_fixate_caps); base_class->query = GST_DEBUG_FUNCPTR (gst_video_rate_query); - g_object_class_install_property (object_class, ARG_IN, + g_object_class_install_property (object_class, PROP_IN, g_param_spec_uint64 ("in", "In", "Number of input frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, ARG_OUT, + g_object_class_install_property (object_class, PROP_OUT, g_param_spec_uint64 ("out", "Out", "Number of output frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); pspec_duplicate = g_param_spec_uint64 ("duplicate", "Duplicate", "Number of duplicated frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, ARG_DUP, pspec_duplicate); + g_object_class_install_property (object_class, PROP_DUP, pspec_duplicate); pspec_drop = g_param_spec_uint64 ("drop", "Drop", "Number of dropped frames", 0, G_MAXUINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, ARG_DROP, pspec_drop); - g_object_class_install_property (object_class, ARG_SILENT, + g_object_class_install_property (object_class, PROP_DROP, pspec_drop); + g_object_class_install_property (object_class, PROP_SILENT, g_param_spec_boolean ("silent", "silent", "Don't emit notify for dropped and duplicated frames", DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, ARG_NEW_PREF, + g_object_class_install_property (object_class, PROP_NEW_PREF, g_param_spec_double ("new-pref", "New Pref", "Value indicating how much to prefer new frames (unused)", 0.0, 1.0, DEFAULT_NEW_PREF, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -228,7 +228,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) * * Since: 0.10.25 */ - g_object_class_install_property (object_class, ARG_SKIP_TO_FIRST, + g_object_class_install_property (object_class, PROP_SKIP_TO_FIRST, g_param_spec_boolean ("skip-to-first", "Skip to first buffer", "Don't produce buffers before the first one we receive", DEFAULT_SKIP_TO_FIRST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -240,7 +240,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) * * Since: 0.10.36 */ - g_object_class_install_property (object_class, ARG_DROP_ONLY, + g_object_class_install_property (object_class, PROP_DROP_ONLY, g_param_spec_boolean ("drop-only", "Only Drop", "Only drop frames, no duplicates are produced", DEFAULT_DROP_ONLY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -254,7 +254,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) * * Since: 0.10.36 */ - g_object_class_install_property (object_class, ARG_AVERAGE_PERIOD, + g_object_class_install_property (object_class, PROP_AVERAGE_PERIOD, g_param_spec_uint64 ("average-period", "Period over which to average", "Period over which to average the framerate (in ns) (0 = disabled)", 0, G_MAXINT64, DEFAULT_AVERAGE_PERIOD, @@ -267,7 +267,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) * * Since: 0.10.36 */ - g_object_class_install_property (object_class, ARG_MAX_RATE, + g_object_class_install_property (object_class, PROP_MAX_RATE, g_param_spec_int ("max-rate", "maximum framerate", "Maximum framerate allowed to pass through " "(in frames per second, implies drop-only)", @@ -281,7 +281,7 @@ gst_video_rate_class_init (GstVideoRateClass * klass) * * Since: 0.10.36 */ - g_object_class_install_property (object_class, ARG_FORCE_FPS, + g_object_class_install_property (object_class, PROP_FORCE_FPS, gst_param_spec_fraction ("force-fps", "Force output framerate", "Force output framerate (negative means negotiate via caps)", -1, 1, G_MAXINT, 1, DEFAULT_FORCE_FPS_N, DEFAULT_FORCE_FPS_D, @@ -1183,27 +1183,27 @@ gst_video_rate_set_property (GObject * object, GST_OBJECT_LOCK (videorate); switch (prop_id) { - case ARG_SILENT: + case PROP_SILENT: videorate->silent = g_value_get_boolean (value); break; - case ARG_NEW_PREF: + case PROP_NEW_PREF: videorate->new_pref = g_value_get_double (value); break; - case ARG_SKIP_TO_FIRST: + case PROP_SKIP_TO_FIRST: videorate->skip_to_first = g_value_get_boolean (value); break; - case ARG_DROP_ONLY: + case PROP_DROP_ONLY: videorate->drop_only = g_value_get_boolean (value); goto reconfigure; break; - case ARG_AVERAGE_PERIOD: + case PROP_AVERAGE_PERIOD: videorate->average_period_set = g_value_get_uint64 (value); break; - case ARG_MAX_RATE: + case PROP_MAX_RATE: g_atomic_int_set (&videorate->max_rate, g_value_get_int (value)); goto reconfigure; break; - case ARG_FORCE_FPS: + case PROP_FORCE_FPS: videorate->force_fps_n = gst_value_get_fraction_numerator (value); videorate->force_fps_d = gst_value_get_fraction_denominator (value); goto reconfigure; @@ -1228,37 +1228,37 @@ gst_video_rate_get_property (GObject * object, GST_OBJECT_LOCK (videorate); switch (prop_id) { - case ARG_IN: + case PROP_IN: g_value_set_uint64 (value, videorate->in); break; - case ARG_OUT: + case PROP_OUT: g_value_set_uint64 (value, videorate->out); break; - case ARG_DUP: + case PROP_DUP: g_value_set_uint64 (value, videorate->dup); break; - case ARG_DROP: + case PROP_DROP: g_value_set_uint64 (value, videorate->drop); break; - case ARG_SILENT: + case PROP_SILENT: g_value_set_boolean (value, videorate->silent); break; - case ARG_NEW_PREF: + case PROP_NEW_PREF: g_value_set_double (value, videorate->new_pref); break; - case ARG_SKIP_TO_FIRST: + case PROP_SKIP_TO_FIRST: g_value_set_boolean (value, videorate->skip_to_first); break; - case ARG_DROP_ONLY: + case PROP_DROP_ONLY: g_value_set_boolean (value, videorate->drop_only); break; - case ARG_AVERAGE_PERIOD: + case PROP_AVERAGE_PERIOD: g_value_set_uint64 (value, videorate->average_period_set); break; - case ARG_MAX_RATE: + case PROP_MAX_RATE: g_value_set_int (value, g_atomic_int_get (&videorate->max_rate)); break; - case ARG_FORCE_FPS: + case PROP_FORCE_FPS: gst_value_set_fraction (value, videorate->force_fps_n, videorate->force_fps_d); break; From 44ec58b41b02ff448bc3f20480eaa1f049afe4d6 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 27 Sep 2011 16:45:26 +0100 Subject: [PATCH 10/18] libgstriff: add a couple tags that need skipping Found in a sample in the wild, appears to be ID3 tag. https://bugzilla.gnome.org/show_bug.cgi?id=660249 --- gst-libs/gst/riff/riff-ids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst-libs/gst/riff/riff-ids.h b/gst-libs/gst/riff/riff-ids.h index 8771d2eb6d..106f71aa7b 100644 --- a/gst-libs/gst/riff/riff-ids.h +++ b/gst-libs/gst/riff/riff-ids.h @@ -46,6 +46,8 @@ G_BEGIN_DECLS #define GST_RIFF_TAG_JUNQ GST_MAKE_FOURCC ('J','U','N','Q') #define GST_RIFF_TAG_idx1 GST_MAKE_FOURCC ('i','d','x','1') #define GST_RIFF_TAG_dmlh GST_MAKE_FOURCC ('d','m','l','h') +#define GST_RIFF_TAG_ID32 GST_MAKE_FOURCC ('I','D','3','2') +#define GST_RIFF_TAG_IDVX GST_MAKE_FOURCC ('I','D','V','X') /* WAV stuff */ #define GST_RIFF_TAG_fmt GST_MAKE_FOURCC ('f','m','t',' ') #define GST_RIFF_TAG_data GST_MAKE_FOURCC ('d','a','t','a') From a5c64d5b97fb3c4012e5e0509ca56f76023b1ba5 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Mon, 24 Oct 2011 11:46:05 +0100 Subject: [PATCH 11/18] oggdemux: minor cleanup --- ext/ogg/gstoggdemux.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ext/ogg/gstoggdemux.c b/ext/ogg/gstoggdemux.c index 16bcf6c23e..58aa56023e 100644 --- a/ext/ogg/gstoggdemux.c +++ b/ext/ogg/gstoggdemux.c @@ -484,6 +484,9 @@ gst_ogg_demux_chain_peer (GstOggPad * pad, ogg_packet * packet, cret = GST_FLOW_OK; + GST_DEBUG_OBJECT (pad, "Chaining %d %d %" GST_TIME_FORMAT " %d %p", + ogg->pullmode, ogg->push_state, GST_TIME_ARGS (ogg->push_time_length), + ogg->push_disable_seeking, ogg->building_chain); GST_PUSH_LOCK (ogg); if (!ogg->pullmode && ogg->push_state == PUSH_PLAYING && ogg->push_time_length == GST_CLOCK_TIME_NONE @@ -1336,15 +1339,18 @@ gst_ogg_demux_estimate_seek_quality (GstOggDemux * ogg) static void gst_ogg_demux_update_bisection_stats (GstOggDemux * ogg) { + int n; + GST_INFO_OBJECT (ogg, "Bisection needed %d + %d steps", ogg->push_bisection_steps[0], ogg->push_bisection_steps[1]); - ogg->stats_bisection_steps[0] += ogg->push_bisection_steps[0]; - ogg->stats_bisection_steps[1] += ogg->push_bisection_steps[1]; - if (ogg->stats_bisection_max_steps[0] < ogg->push_bisection_steps[0]) - ogg->stats_bisection_max_steps[0] = ogg->push_bisection_steps[0]; - if (ogg->stats_bisection_max_steps[1] < ogg->push_bisection_steps[1]) - ogg->stats_bisection_max_steps[1] = ogg->push_bisection_steps[1]; + + for (n = 0; n < 2; ++n) { + ogg->stats_bisection_steps[n] += ogg->push_bisection_steps[n]; + if (ogg->stats_bisection_max_steps[n] < ogg->push_bisection_steps[n]) + ogg->stats_bisection_max_steps[n] = ogg->push_bisection_steps[n]; + } ogg->stats_nbisections++; + GST_INFO_OBJECT (ogg, "So far, %.2f + %.2f bisections needed per seek (max %d + %d)", ogg->stats_bisection_steps[0] / (float) ogg->stats_nbisections, From 59f5d980f60a7fe10c8088bd32a08448709bdc79 Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 8 Nov 2011 13:55:58 +0000 Subject: [PATCH 12/18] decodebin2: fix prerolling for low bitrate streams from hlsdemux Such streams were detected as seekable, as the query on the typefind element was testing the m3u8 file listing the actual streams, and not going through the demuxer(s). We now check for seekability for each multiqueue following a demuxer, so the query will flow through the elements which might prevent seeking. https://bugzilla.gnome.org/show_bug.cgi?id=647769 --- gst/playback/gstdecodebin2.c | 50 ++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 520416b8c4..3e8268f026 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -174,8 +174,6 @@ struct _GstDecodeBin gboolean expose_allstreams; /* Whether to expose unknow type streams or not */ - gboolean upstream_seekable; /* if upstream is seekable */ - GList *filtered; /* elements for which error messages are filtered */ }; @@ -275,7 +273,7 @@ static void type_found (GstElement * typefind, guint probability, GstCaps * caps, GstDecodeBin * decode_bin); static void decodebin_set_queue_size (GstDecodeBin * dbin, - GstElement * multiqueue, gboolean preroll); + GstElement * multiqueue, gboolean preroll, gboolean seekable); static gboolean gst_decode_bin_autoplug_continue (GstElement * element, GstPad * pad, GstCaps * caps); @@ -300,6 +298,8 @@ static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element, GstStateChange transition); static void gst_decode_bin_handle_message (GstBin * bin, GstMessage * message); +static gboolean check_upstream_seekable (GstDecodeBin * dbin, GstPad * pad); + #define EXPOSE_LOCK(dbin) G_STMT_START { \ GST_LOG_OBJECT (dbin, \ "expose locking from thread %p", \ @@ -2204,28 +2204,26 @@ beach: * * Check if upstream is seekable. */ -static void +static gboolean check_upstream_seekable (GstDecodeBin * dbin, GstPad * pad) { GstQuery *query; gint64 start = -1, stop = -1; - - dbin->upstream_seekable = FALSE; + gboolean seekable = FALSE; query = gst_query_new_seeking (GST_FORMAT_BYTES); if (!gst_pad_peer_query (pad, query)) { GST_DEBUG_OBJECT (dbin, "seeking query failed"); gst_query_unref (query); - return; + return FALSE; } - gst_query_parse_seeking (query, NULL, &dbin->upstream_seekable, - &start, &stop); + gst_query_parse_seeking (query, NULL, &seekable, &start, &stop); gst_query_unref (query); /* try harder to query upstream size if we didn't get it the first time */ - if (dbin->upstream_seekable && stop == -1) { + if (seekable && stop == -1) { GstFormat fmt = GST_FORMAT_BYTES; GST_DEBUG_OBJECT (dbin, "doing duration query to fix up unset stop"); @@ -2234,12 +2232,13 @@ check_upstream_seekable (GstDecodeBin * dbin, GstPad * pad) /* if upstream doesn't know the size, it's likely that it's not seekable in * practice even if it technically may be seekable */ - if (dbin->upstream_seekable && (start != 0 || stop <= start)) { + if (seekable && (start != 0 || stop <= start)) { GST_DEBUG_OBJECT (dbin, "seekable but unknown start/stop -> disable"); - dbin->upstream_seekable = FALSE; + return FALSE; } - GST_DEBUG_OBJECT (dbin, "upstream seekable: %d", dbin->upstream_seekable); + GST_DEBUG_OBJECT (dbin, "upstream seekable: %d", seekable); + return seekable; } static void @@ -2270,10 +2269,6 @@ type_found (GstElement * typefind, guint probability, pad = gst_element_get_static_pad (typefind, "src"); sink_pad = gst_element_get_static_pad (typefind, "sink"); - /* if upstream is seekable we can safely set a limit in time to the queues so - * that streams at low bitrates can preroll */ - check_upstream_seekable (decode_bin, sink_pad); - /* need some lock here to prevent race with shutdown state change * which might yank away e.g. decode_chain while building stuff here. * In typical cases, STREAM_LOCK is held and handles that, it need not @@ -2406,7 +2401,7 @@ no_more_pads_cb (GstElement * element, GstDecodeChain * chain) * we can probably set its buffering state to playing now */ GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " "'playing' buffering mode", group); - decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE); + decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, TRUE); CHAIN_MUTEX_UNLOCK (chain); EXPOSE_LOCK (chain->dbin); @@ -2862,7 +2857,7 @@ gst_decode_group_hide (GstDecodeGroup * group) * playing or prerolling. */ static void decodebin_set_queue_size (GstDecodeBin * dbin, GstElement * multiqueue, - gboolean preroll) + gboolean preroll, gboolean seekable) { guint max_bytes, max_buffers; guint64 max_time; @@ -2875,7 +2870,7 @@ decodebin_set_queue_size (GstDecodeBin * dbin, GstElement * multiqueue, if ((max_buffers = dbin->max_size_buffers) == 0) max_buffers = AUTO_PREROLL_SIZE_BUFFERS; if ((max_time = dbin->max_size_time) == 0) - max_time = dbin->upstream_seekable ? AUTO_PREROLL_SEEKABLE_SIZE_TIME : + max_time = seekable ? AUTO_PREROLL_SEEKABLE_SIZE_TIME : AUTO_PREROLL_NOT_SEEKABLE_SIZE_TIME; } else { /* update runtime limits. At runtime, we try to keep the amount of buffers @@ -2905,6 +2900,7 @@ gst_decode_group_new (GstDecodeBin * dbin, GstDecodeChain * parent) { GstDecodeGroup *group = g_slice_new0 (GstDecodeGroup); GstElement *mq; + gboolean seekable; GST_DEBUG_OBJECT (dbin, "Creating new group %p with parent chain %p", group, parent); @@ -2925,7 +2921,17 @@ gst_decode_group_new (GstDecodeBin * dbin, GstDecodeChain * parent) } /* configure queue sizes for preroll */ - decodebin_set_queue_size (dbin, mq, TRUE); + seekable = FALSE; + if (parent && parent->demuxer) { + GstElement *element = + ((GstDecodeElement *) parent->elements->data)->element; + GstPad *pad = gst_element_get_static_pad (element, "sink"); + if (pad) { + seekable = check_upstream_seekable (dbin, pad); + gst_object_unref (pad); + } + } + decodebin_set_queue_size (dbin, mq, TRUE, seekable); group->overrunsig = g_signal_connect (G_OBJECT (mq), "overrun", G_CALLBACK (multi_queue_overrun_cb), group); @@ -3687,7 +3693,7 @@ gst_decode_chain_expose (GstDecodeChain * chain, GList ** endpads, dbin = group->dbin; /* configure queues for playback */ - decodebin_set_queue_size (dbin, group->multiqueue, FALSE); + decodebin_set_queue_size (dbin, group->multiqueue, FALSE, TRUE); /* we can now disconnect any overrun signal, which is used to expose the * group. */ From 494b2cb1a72ce3350e174ba60550a81eae5dfa56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Nov 2011 11:08:58 +0100 Subject: [PATCH 13/18] decodebin2: Cache the upstream seekability for demuxer decode chains and use it for the non-preroll multiqueue limits After preroll the multiqueue limits are still set to the preroll limits if use-buffering is set to TRUE. In that case we only want time limits on the multiqueue if upstream is seekable. --- gst/playback/gstdecodebin2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 3e8268f026..ecf2a4d7c1 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -400,6 +400,7 @@ struct _GstDecodeChain GstPad *pad; /* srcpad that caused creation of this chain */ gboolean demuxer; /* TRUE if elements->data is a demuxer */ + gboolean seekable; /* TRUE if this chain ends on a demuxer and is seekable */ GList *elements; /* All elements in this group, first is the latest and most downstream element */ @@ -2401,7 +2402,8 @@ no_more_pads_cb (GstElement * element, GstDecodeChain * chain) * we can probably set its buffering state to playing now */ GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " "'playing' buffering mode", group); - decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, TRUE); + decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, + (group->parent ? group->parent->seekable : TRUE)); CHAIN_MUTEX_UNLOCK (chain); EXPOSE_LOCK (chain->dbin); @@ -2927,7 +2929,7 @@ gst_decode_group_new (GstDecodeBin * dbin, GstDecodeChain * parent) ((GstDecodeElement *) parent->elements->data)->element; GstPad *pad = gst_element_get_static_pad (element, "sink"); if (pad) { - seekable = check_upstream_seekable (dbin, pad); + seekable = parent->seekable = check_upstream_seekable (dbin, pad); gst_object_unref (pad); } } From a5535e76e069e1b304298ad56147b023a436bfaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 25 Nov 2011 11:11:12 +0100 Subject: [PATCH 14/18] decodebin2: Set the multiqueue limits to the playing limits after overrun too We don't expect any new pads anymore and prerolling is finished now. --- gst/playback/gstdecodebin2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index ecf2a4d7c1..2d6f8579c2 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -2754,6 +2754,12 @@ multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group) queue); group->overrun = TRUE; + /* this group has prerolled enough to not need more pads, + * we can probably set its buffering state to playing now */ + GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " + "'playing' buffering mode", group); + decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, + (group->parent ? group->parent->seekable : TRUE)); /* FIXME: We should make sure that everything gets exposed now * even if child chains are not complete because the will never From 2dc7c2f676248f919b9ee0ff836a2ddca8570cb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 25 Nov 2011 12:58:22 +0000 Subject: [PATCH 15/18] docs: mention explicitly that playbin2 signals are emitted from a streaming thread --- gst/playback/gstplaybin2.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 7c53864228..1e8a7996d7 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -825,6 +825,8 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * * This signal is emitted when the current uri is about to finish. You can * set the uri and suburi to make sure that playback continues. + * + * This signal is emitted from the context of a GStreamer streaming thread. */ gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] = g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass), @@ -839,7 +841,12 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the number or order of the video * streams has changed. The application will most likely want to select * a new video stream. + * + * This signal is usually emitted from the context of a GStreamer streaming + * thread. You can use gst_message_new_application() and + * gst_element_post_message() to notify your application's main thread. */ + /* FIXME 0.11: turn video-changed signal into message? */ gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] = g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -852,7 +859,12 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the number or order of the audio * streams has changed. The application will most likely want to select * a new audio stream. + * + * This signal may be emitted from the context of a GStreamer streaming thread. + * You can use gst_message_new_application() and gst_element_post_message() + * to notify your application's main thread. */ + /* FIXME 0.11: turn audio-changed signal into message? */ gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] = g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -865,7 +877,12 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the number or order of the text * streams has changed. The application will most likely want to select * a new text stream. + * + * This signal may be emitted from the context of a GStreamer streaming thread. + * You can use gst_message_new_application() and gst_element_post_message() + * to notify your application's main thread. */ + /* FIXME 0.11: turn text-changed signal into message? */ gst_play_bin_signals[SIGNAL_TEXT_CHANGED] = g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -880,6 +897,10 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the tags of a video stream have changed. * The application will most likely want to get the new tags. * + * This signal may be emitted from the context of a GStreamer streaming thread. + * You can use gst_message_new_application() and gst_element_post_message() + * to notify your application's main thread. + * * Since: 0.10.24 */ gst_play_bin_signals[SIGNAL_VIDEO_TAGS_CHANGED] = @@ -896,6 +917,10 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the tags of an audio stream have changed. * The application will most likely want to get the new tags. * + * This signal may be emitted from the context of a GStreamer streaming thread. + * You can use gst_message_new_application() and gst_element_post_message() + * to notify your application's main thread. + * * Since: 0.10.24 */ gst_play_bin_signals[SIGNAL_AUDIO_TAGS_CHANGED] = @@ -912,6 +937,10 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * This signal is emitted whenever the tags of a text stream have changed. * The application will most likely want to get the new tags. * + * This signal may be emitted from the context of a GStreamer streaming thread. + * You can use gst_message_new_application() and gst_element_post_message() + * to notify your application's main thread. + * * Since: 0.10.24 */ gst_play_bin_signals[SIGNAL_TEXT_TAGS_CHANGED] = @@ -931,6 +960,9 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * an audio cd source). This is functionally equivalent to connecting to * the notify::source signal, but more convenient. * + * This signal is usually emitted from the context of a GStreamer streaming + * thread. + * * Since: 0.10.33 */ gst_play_bin_signals[SIGNAL_SOURCE_SETUP] = From a0639dad38a4f82dbff4284ef60d482f0172f456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Fri, 25 Nov 2011 13:11:54 +0000 Subject: [PATCH 16/18] audio: remove unstable API guards from the audio decoder and encoder base classes --- ext/vorbis/Makefile.am | 4 ++-- gst-libs/gst/audio/Makefile.am | 1 - gst-libs/gst/audio/gstaudiodecoder.c | 1 - gst-libs/gst/audio/gstaudiodecoder.h | 5 ----- gst-libs/gst/audio/gstaudioencoder.c | 1 - gst-libs/gst/audio/gstaudioencoder.h | 5 ----- 6 files changed, 2 insertions(+), 15 deletions(-) diff --git a/ext/vorbis/Makefile.am b/ext/vorbis/Makefile.am index 9678a31b9e..81799bd607 100644 --- a/ext/vorbis/Makefile.am +++ b/ext/vorbis/Makefile.am @@ -11,7 +11,7 @@ libgstvorbis_la_SOURCES = gstvorbis.c \ gstvorbistag.c \ gstvorbiscommon.c -libgstvorbis_la_CFLAGS = -DGST_USE_UNSTABLE_API \ +libgstvorbis_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(VORBIS_CFLAGS) ## AM_PATH_VORBIS also sets VORBISENC_LIBS libgstvorbis_la_LIBADD = \ @@ -28,7 +28,7 @@ plugin_LTLIBRARIES += libgstivorbisdec.la libgstivorbisdec_la_SOURCES = gstivorbisdec.c \ gstvorbisdec.c gstvorbisdeclib.c gstvorbiscommon.c -libgstivorbisdec_la_CFLAGS = -DGST_USE_UNSTABLE_API \ +libgstivorbisdec_la_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ -DTREMOR $(IVORBIS_CFLAGS) libgstivorbisdec_la_LIBADD = \ diff --git a/gst-libs/gst/audio/Makefile.am b/gst-libs/gst/audio/Makefile.am index 882b611858..6e89c471df 100644 --- a/gst-libs/gst/audio/Makefile.am +++ b/gst-libs/gst/audio/Makefile.am @@ -77,7 +77,6 @@ GstAudio-@GST_MAJORMINOR@.gir: $(INTROSPECTION_SCANNER) libgstaudio-@GST_MAJORMI $(INTROSPECTION_SCANNER) -v --namespace GstAudio \ --nsversion=@GST_MAJORMINOR@ \ --strip-prefix=Gst \ - -DGST_USE_UNSTABLE_API \ -I$(top_srcdir)/gst-libs \ -I$(top_builddir)/gst-libs \ $(gir_cincludes) \ diff --git a/gst-libs/gst/audio/gstaudiodecoder.c b/gst-libs/gst/audio/gstaudiodecoder.c index a45e4e53bb..0f5d7ccd58 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.c +++ b/gst-libs/gst/audio/gstaudiodecoder.c @@ -149,7 +149,6 @@ #include "config.h" #endif -#define GST_USE_UNSTABLE_API #include "gstaudiodecoder.h" #include diff --git a/gst-libs/gst/audio/gstaudiodecoder.h b/gst-libs/gst/audio/gstaudiodecoder.h index 783f83ea42..b080163a0a 100644 --- a/gst-libs/gst/audio/gstaudiodecoder.h +++ b/gst-libs/gst/audio/gstaudiodecoder.h @@ -23,11 +23,6 @@ #ifndef _GST_AUDIO_DECODER_H_ #define _GST_AUDIO_DECODER_H_ -#ifndef GST_USE_UNSTABLE_API -#warning "GstAudioDecoder is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - #include #include #include diff --git a/gst-libs/gst/audio/gstaudioencoder.c b/gst-libs/gst/audio/gstaudioencoder.c index 14064f03bd..ded750212d 100644 --- a/gst-libs/gst/audio/gstaudioencoder.c +++ b/gst-libs/gst/audio/gstaudioencoder.c @@ -151,7 +151,6 @@ # include "config.h" #endif -#define GST_USE_UNSTABLE_API #include "gstaudioencoder.h" #include #include diff --git a/gst-libs/gst/audio/gstaudioencoder.h b/gst-libs/gst/audio/gstaudioencoder.h index 263a635d92..523d39a927 100644 --- a/gst-libs/gst/audio/gstaudioencoder.h +++ b/gst-libs/gst/audio/gstaudioencoder.h @@ -22,11 +22,6 @@ #ifndef __GST_AUDIO_ENCODER_H__ #define __GST_AUDIO_ENCODER_H__ -#ifndef GST_USE_UNSTABLE_API -#warning "GstAudioEncoder is unstable API and may change in future." -#warning "You can define GST_USE_UNSTABLE_API to avoid this warning." -#endif - #include #include From 05ecdc124636ff7804b860eed20e358e1cc688b2 Mon Sep 17 00:00:00 2001 From: Josep Torra Date: Fri, 25 Nov 2011 15:35:39 +0100 Subject: [PATCH 17/18] playsinkconvertbin: make identiy silent --- gst/playback/gstplaysinkconvertbin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gst/playback/gstplaysinkconvertbin.c b/gst/playback/gstplaysinkconvertbin.c index d49224d58b..361b5d20c1 100644 --- a/gst/playback/gstplaysinkconvertbin.c +++ b/gst/playback/gstplaysinkconvertbin.c @@ -142,6 +142,8 @@ gst_play_sink_convert_bin_add_identity (GstPlaySinkConvertBin * self) ); } else { + g_object_set (self->identity, "silent", TRUE, "signal-handoffs", FALSE, + NULL); gst_bin_add (GST_BIN_CAST (self), self->identity); } } From c6b9145630373f82cb82040bf54c0189bab416db Mon Sep 17 00:00:00 2001 From: Vincent Penquerc'h Date: Tue, 1 Nov 2011 15:21:54 +0000 Subject: [PATCH 18/18] oggmux: set collectpads2 not to wait on sparse streams https://bugzilla.gnome.org/show_bug.cgi?id=663174 --- ext/ogg/gstoggmux.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index 5341d6ca9a..06133e30f0 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -465,7 +465,7 @@ gst_ogg_mux_request_new_pad (GstElement * element, oggpad = (GstOggPadData *) gst_collect_pads2_add_pad_full (ogg_mux->collect, newpad, - sizeof (GstOggPadData), gst_ogg_mux_ogg_pad_destroy_notify, TRUE); + sizeof (GstOggPadData), gst_ogg_mux_ogg_pad_destroy_notify, FALSE); ogg_mux->active_pads++; oggpad->map.serialno = serial; @@ -987,6 +987,12 @@ gst_ogg_mux_queue_pads (GstOggMux * ogg_mux, gboolean * popped) } else { GST_DEBUG_OBJECT (pad, "caps detected: %" GST_PTR_FORMAT, pad->map.caps); + + if (pad->map.is_sparse) { + GST_DEBUG_OBJECT (pad, "Pad is sparse, marking as such"); + gst_collect_pads2_set_waiting (ogg_mux->collect, + (GstCollectData2 *) pad, FALSE); + } } } @@ -1339,8 +1345,8 @@ gst_ogg_mux_send_headers (GstOggMux * mux) GST_LOG_OBJECT (mux, "looking at pad %s:%s", GST_DEBUG_PAD_NAME (thepad)); - /* if the pad has no buffer, we don't care */ - if (pad->buffer == NULL) + /* if the pad has no buffer and is not sparse, we don't care */ + if (pad->buffer == NULL && !pad->map.is_sparse) continue; /* now figure out the headers */