diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index 017a7f5806..adea05fdba 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -619,9 +619,13 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - /* handle seeking */ - res = gst_avi_demux_handle_seek (avi, pad, event); - gst_event_unref (event); + /* handle seeking only in pull mode */ + if (!avi->streaming) { + res = gst_avi_demux_handle_seek (avi, pad, event); + gst_event_unref (event); + } else { + res = gst_pad_event_default (pad, event); + } break; case GST_EVENT_QOS: case GST_EVENT_NAVIGATION: @@ -4246,6 +4250,7 @@ gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) if (active) { avi->segment_running = TRUE; + avi->streaming = FALSE; return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop, sinkpad); } else { @@ -4257,9 +4262,11 @@ gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active) static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active) { + GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (pad)); if (active) { GST_DEBUG ("avi: activating push/chain function"); + avi->streaming = TRUE; } else { GST_DEBUG ("avi: deactivating push/chain function"); } diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 118886fc75..50011cffd1 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -5135,9 +5135,6 @@ gst_matroska_demux_video_caps (GstMatroskaTrackVideoContext * guint rformat; guint subformat; - gst_util_dump_mem (data, size); - gst_util_dump_mem (data + 0x1a, size - 0x1a); - subformat = GST_READ_UINT32_BE (data + 0x1a); rformat = GST_READ_UINT32_BE (data + 0x1e); @@ -5503,7 +5500,6 @@ gst_matroska_demux_audio_caps (GstMatroskaTrackAudioContext * guint extra_data_size; GST_ERROR ("real audio raversion:%d", raversion); - gst_util_dump_mem (data, size); if (raversion == 8) { /* COOK */ flavor = GST_READ_UINT16_BE (data + 22); diff --git a/gst/replaygain/gstrgvolume.c b/gst/replaygain/gstrgvolume.c index 41fe441d4c..d569b4bb40 100644 --- a/gst/replaygain/gstrgvolume.c +++ b/gst/replaygain/gstrgvolume.c @@ -92,7 +92,7 @@ enum #define PEAK_FORMAT ".06f" #define VALID_GAIN(x) ((x) > -60.00 && (x) < 60.00) -#define VALID_PEAK(x) ((x) > 0.) +#define VALID_PEAK(x) ((x) > 0. && (x) < 1.) /* Same template caps as GstVolume, for I don't like having just ANY caps. */ diff --git a/gst/rtp/gstrtpvrawdepay.c b/gst/rtp/gstrtpvrawdepay.c index 35e68a3e4a..3f599f5dbc 100644 --- a/gst/rtp/gstrtpvrawdepay.c +++ b/gst/rtp/gstrtpvrawdepay.c @@ -139,6 +139,11 @@ gst_rtp_vraw_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps) goto no_height; height = atoi (str); + /* optional interlace value but we don't handle interlaced + * formats yet */ + if ((str = gst_structure_get_string (structure, "interlace"))) + goto interlaced; + if (!(str = gst_structure_get_string (structure, "sampling"))) goto no_sampling; @@ -248,6 +253,11 @@ no_height: GST_ERROR_OBJECT (depayload, "no height specified"); return FALSE; } +interlaced: + { + GST_ERROR_OBJECT (depayload, "interlaced formats not supported yet"); + return FALSE; + } no_sampling: { GST_ERROR_OBJECT (depayload, "no sampling specified"); diff --git a/gst/rtp/gstrtpvrawpay.c b/gst/rtp/gstrtpvrawpay.c index 19c14c2bc9..0f0ef7e826 100644 --- a/gst/rtp/gstrtpvrawpay.c +++ b/gst/rtp/gstrtpvrawpay.c @@ -211,6 +211,7 @@ gst_rtp_vraw_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) GstVideoFormat sampling; const gchar *depthstr, *samplingstr, *colorimetrystr; gchar *wstr, *hstr; + gboolean interlaced; rtpvrawpay = GST_RTP_VRAW_PAY (payload); @@ -229,6 +230,13 @@ gst_rtp_vraw_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps) if (!res) goto missing_dimension; + /* fail on interlaced video for now */ + if (!gst_structure_get_boolean (s, "interlaced", &interlaced)) + interlaced = FALSE; + + if (interlaced) + goto interlaced; + yp = up = vp = 0; xinc = yinc = 1; @@ -358,6 +366,11 @@ unknown_fourcc: GST_ERROR_OBJECT (payload, "invalid or missing fourcc"); return FALSE; } +interlaced: + { + GST_ERROR_OBJECT (payload, "interlaced video not supported yet"); + return FALSE; + } missing_dimension: { GST_ERROR_OBJECT (payload, "missing width or height property"); @@ -409,7 +422,7 @@ gst_rtp_vraw_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer) GstBuffer *out; guint8 *outdata, *headers; gboolean next_line; - guint length, cont, pixels; + guint length, cont, pixels, fieldid; /* get the max allowed payload length size, we try to fill the complete MTU */ left = gst_rtp_buffer_calc_payload_len (mtu, 0, 0); @@ -422,6 +435,24 @@ gst_rtp_vraw_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer) GST_LOG_OBJECT (rtpvrawpay, "created buffer of size %u for MTU %u", left, mtu); + /* + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Extended Sequence Number | Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |F| Line No |C| Offset | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Length |F| Line No | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |C| Offset | . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ . + * . . + * . Two (partial) lines of video data . + * . . + * +---------------------------------------------------------------+ + */ + /* need 2 bytes for the extended sequence number */ *outdata++ = 0; *outdata++ = 0; @@ -456,8 +487,12 @@ gst_rtp_vraw_pay_handle_buffer (GstBaseRTPPayload * payload, GstBuffer * buffer) /* write length */ *outdata++ = (length >> 8) & 0xff; *outdata++ = length & 0xff; + + /* always 0 for now */ + fieldid = 0x00; + /* write line no */ - *outdata++ = (line >> 8) & 0x7f; + *outdata++ = ((line >> 8) & 0x7f) | fieldid; *outdata++ = line & 0xff; if (next_line) { diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index b3e1df47b0..7c5ef8a6b5 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -146,6 +146,7 @@ enum #define DEFAULT_LATENCY_MS 3000 #define DEFAULT_CONNECTION_SPEED 0 #define DEFAULT_NAT_METHOD GST_RTSP_NAT_DUMMY +#define DEFAULT_DO_RTCP TRUE enum { @@ -159,6 +160,7 @@ enum PROP_LATENCY, PROP_CONNECTION_SPEED, PROP_NAT_METHOD, + PROP_DO_RTCP, PROP_LAST }; @@ -335,6 +337,19 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass) GST_TYPE_RTSP_NAT_METHOD, DEFAULT_NAT_METHOD, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + /** + * GstRTSPSrc::do-rtcp + * + * Enable RTCP support. Some old server don't like RTCP and then this property + * needs to be set to FALSE. + * + * Since: 0.10.15 + */ + g_object_class_install_property (gobject_class, PROP_DO_RTCP, + g_param_spec_boolean ("do-rtcp", "Do RTCP", + "Don't send RTCP packets", + DEFAULT_DO_RTCP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + gstelement_class->change_state = gst_rtspsrc_change_state; gstbin_class->handle_message = gst_rtspsrc_handle_message; @@ -454,6 +469,9 @@ gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value, case PROP_NAT_METHOD: rtspsrc->nat_method = g_value_get_enum (value); break; + case PROP_DO_RTCP: + rtspsrc->do_rtcp = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -502,6 +520,9 @@ gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value, case PROP_NAT_METHOD: g_value_set_enum (value, rtspsrc->nat_method); break; + case PROP_DO_RTCP: + g_value_set_boolean (value, rtspsrc->do_rtcp); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1942,8 +1963,8 @@ gst_rtspsrc_stream_configure_tcp (GstRTSPSrc * src, GstRTSPStream * stream, } gst_object_unref (template); } - /* setup RTCP transport back to the server */ - if (src->session) { + /* setup RTCP transport back to the server if we have to. */ + if (src->session && src->do_rtcp) { GstPad *pad; template = gst_static_pad_template_get (&anysinktemplate); @@ -2162,7 +2183,7 @@ gst_rtspsrc_stream_configure_udp_sinks (GstRTSPSrc * src, } /* it's possible that the server does not want us to send RTCP in which case * the port is -1 */ - if (rtcp_port != -1 && src->session != NULL) { + if (rtcp_port != -1 && src->session != NULL && src->do_rtcp) { GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination, rtcp_port); @@ -3944,7 +3965,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src) GST_DEBUG_OBJECT (src, "doing setup of stream %p with %s", stream, stream->setup_url); -retry: + retry: /* create a string with all the transports */ res = gst_rtspsrc_create_transports_string (src, protocols, &transports); if (res < 0) diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index 95dd986913..40a368c6d7 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -186,6 +186,7 @@ struct _GstRTSPSrc { guint latency; guint connection_speed; GstRTSPNatMethod nat_method; + gboolean do_rtcp; /* state */ GstRTSPState state; diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c index 07268509e2..5fa7593afa 100644 --- a/gst/udp/gstudpnetutils.c +++ b/gst/udp/gstudpnetutils.c @@ -115,12 +115,17 @@ beach: int gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl) { + socklen_t socklen; + struct sockaddr_storage addr; int ret = -1; - -#if 0 int l = (loop == FALSE) ? 0 : 1; - switch (addr->ss_family) { + socklen = sizeof (addr); + if ((ret = getsockname (sockfd, (struct sockaddr *) &addr, &socklen)) < 0) { + return ret; + } + + switch (addr.ss_family) { case AF_INET: { if ((ret = @@ -155,7 +160,6 @@ gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl) errno = EAFNOSUPPORT; #endif } -#endif return ret; } diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index 266c430fac..c8e7c756ef 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -77,6 +77,7 @@ static gboolean gst_wavparse_pad_convert (GstPad * pad, gint64 src_value, GstFormat * dest_format, gint64 * dest_value); static GstFlowReturn gst_wavparse_chain (GstPad * pad, GstBuffer * buf); +static gboolean gst_wavparse_sink_event (GstPad * pad, GstEvent * event); static void gst_wavparse_loop (GstPad * pad); static gboolean gst_wavparse_srcpad_event (GstPad * pad, GstEvent * event); @@ -193,6 +194,8 @@ gst_wavparse_init (GstWavParse * wavparse, GstWavParseClass * g_class) GST_DEBUG_FUNCPTR (gst_wavparse_sink_activate_pull)); gst_pad_set_chain_function (wavparse->sinkpad, GST_DEBUG_FUNCPTR (gst_wavparse_chain)); + gst_pad_set_event_function (wavparse->sinkpad, + GST_DEBUG_FUNCPTR (gst_wavparse_sink_event)); gst_element_add_pad (GST_ELEMENT_CAST (wavparse), wavparse->sinkpad); /* src, will be created later */ @@ -725,8 +728,35 @@ gst_wavparse_stream_init (GstWavParse * wav) return GST_FLOW_OK; } -/* This function is used to perform seeks on the element in - * pull mode. +static gboolean +gst_wavparse_time_to_bytepos (GstWavParse * wav, gint64 ts, gint64 * bytepos) +{ + /* -1 always maps to -1 */ + if (ts == -1) { + *bytepos = -1; + return TRUE; + } + + /* 0 always maps to 0 */ + if (ts == 0) { + *bytepos = 0; + return TRUE; + } + + if (wav->bps > 0) { + *bytepos = uint64_ceiling_scale (ts, (guint64) wav->bps, GST_SECOND); + return TRUE; + } else if (wav->fact) { + guint64 bps = + gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); + *bytepos = uint64_ceiling_scale (ts, bps, GST_SECOND); + return TRUE; + } + + return FALSE; +} + +/* This function is used to perform seeks on the element. * * It also works when event is NULL, in which case it will just * start from the last configured segment. This technique is @@ -783,6 +813,48 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) stop_type = GST_SEEK_TYPE_SET; } + /* in push mode, we must delegate to upstream */ + if (wav->streaming) { + gboolean res = FALSE; + + /* if streaming not yet started; only prepare initial newsegment */ + if (!event || wav->state != GST_WAVPARSE_DATA) { + if (wav->start_segment) + gst_event_unref (wav->start_segment); + wav->start_segment = + gst_event_new_new_segment (FALSE, wav->segment.rate, + wav->segment.format, wav->segment.last_stop, wav->segment.duration, + wav->segment.last_stop); + res = TRUE; + } else { + /* convert seek positions to byte positions in data sections */ + if (format == GST_FORMAT_TIME) { + /* should not fail */ + if (!gst_wavparse_time_to_bytepos (wav, cur, &cur)) + goto no_position; + if (!gst_wavparse_time_to_bytepos (wav, stop, &stop)) + goto no_position; + } + /* mind sample boundary and header */ + if (cur >= 0) { + cur -= (cur % wav->bytes_per_sample); + cur += wav->datastart; + } + if (stop >= 0) { + stop -= (stop % wav->bytes_per_sample); + stop += wav->datastart; + } + GST_DEBUG_OBJECT (wav, "Pushing BYTE seek rate %g, " + "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, cur, + stop); + /* BYTE seek event */ + event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, cur, + stop_type, stop); + res = gst_pad_push_event (wav->sinkpad, event); + } + return res; + } + /* get flush flag */ flush = flags & GST_SEEK_FLAG_FLUSH; @@ -832,16 +904,8 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and * we can just copy the last_stop. If not, we use the bps to convert TIME to * bytes. */ - if (wav->bps > 0) - wav->offset = - uint64_ceiling_scale (seeksegment.last_stop, (guint64) wav->bps, - GST_SECOND); - else if (wav->fact) { - guint64 bps = - gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); - wav->offset = - uint64_ceiling_scale (seeksegment.last_stop, bps, GST_SECOND); - } else + if (!gst_wavparse_time_to_bytepos (wav, seeksegment.last_stop, + (gint64 *) & wav->offset)) wav->offset = seeksegment.last_stop; GST_LOG_OBJECT (wav, "offset=%" G_GUINT64_FORMAT, wav->offset); wav->offset -= (wav->offset % wav->bytes_per_sample); @@ -854,14 +918,7 @@ gst_wavparse_perform_seek (GstWavParse * wav, GstEvent * event) } if (stop_type != GST_SEEK_TYPE_NONE) { - if (wav->bps > 0) - wav->end_offset = - uint64_ceiling_scale (stop, (guint64) wav->bps, GST_SECOND); - else if (wav->fact) { - guint64 bps = - gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); - wav->end_offset = uint64_ceiling_scale (stop, bps, GST_SECOND); - } else + if (!gst_wavparse_time_to_bytepos (wav, stop, (gint64 *) & wav->end_offset)) wav->end_offset = stop; GST_LOG_OBJECT (wav, "end_offset=%" G_GUINT64_FORMAT, wav->end_offset); wav->end_offset -= (wav->end_offset % wav->bytes_per_sample); @@ -962,6 +1019,12 @@ no_format: GST_DEBUG_OBJECT (wav, "unsupported format given, seek aborted."); return FALSE; } +no_position: + { + GST_DEBUG_OBJECT (wav, + "Could not determine byte position for desired time"); + return FALSE; + } } /* @@ -1678,6 +1741,32 @@ iterate_adapter: if (wav->streaming) { guint avail = gst_adapter_available (wav->adapter); + guint extra; + + /* flush some bytes if evil upstream sends segment that starts + * before data or does is not send sample aligned segment */ + if (G_LIKELY (wav->offset >= wav->datastart)) { + extra = (wav->offset - wav->datastart) % wav->bytes_per_sample; + } else { + extra = wav->datastart - wav->offset; + } + + if (G_UNLIKELY (extra)) { + extra = wav->bytes_per_sample - extra; + if (extra <= avail) { + GST_DEBUG_OBJECT (wav, "flushing %d bytes to sample boundary", extra); + gst_adapter_flush (wav->adapter, extra); + wav->offset += extra; + wav->dataleft -= extra; + goto iterate_adapter; + } else { + GST_DEBUG_OBJECT (wav, "flushing %d bytes", avail); + gst_adapter_clear (wav->adapter); + wav->offset += avail; + wav->dataleft -= avail; + return GST_FLOW_OK; + } + } if (avail < desired) { GST_LOG_OBJECT (wav, "Got only %d bytes of data from the sinkpad", avail); @@ -1927,6 +2016,8 @@ gst_wavparse_chain (GstPad * pad, GstBuffer * buf) /* fall-through */ case GST_WAVPARSE_DATA: + if (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) + wav->discont = TRUE; if ((ret = gst_wavparse_stream_data (wav)) != GST_FLOW_OK) goto done; break; @@ -1937,6 +2028,132 @@ done: return ret; } +static GstFlowReturn +gst_wavparse_flush_data (GstWavParse * wav) +{ + GstFlowReturn ret = GST_FLOW_OK; + guint av; + + if ((av = gst_adapter_available (wav->adapter)) > 0) { + wav->dataleft = av; + wav->end_offset = wav->offset + av; + ret = gst_wavparse_stream_data (wav); + } + + return ret; +} + +static gboolean +gst_wavparse_sink_event (GstPad * pad, GstEvent * event) +{ + GstWavParse *wav = GST_WAVPARSE (GST_PAD_PARENT (pad)); + gboolean ret = TRUE; + + GST_LOG_OBJECT (wav, "handling %s event", GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NEWSEGMENT: + { + GstFormat format; + gdouble rate, arate; + gint64 start, stop, time, offset = 0, end_offset = -1; + gboolean update; + GstSegment segment; + + /* some debug output */ + gst_segment_init (&segment, GST_FORMAT_UNDEFINED); + gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, + &start, &stop, &time); + gst_segment_set_newsegment_full (&segment, update, rate, arate, format, + start, stop, time); + GST_DEBUG_OBJECT (wav, + "received format %d newsegment %" GST_SEGMENT_FORMAT, format, + &segment); + + if (wav->state != GST_WAVPARSE_DATA) { + GST_DEBUG_OBJECT (wav, "still starting, eating event"); + goto exit; + } + + /* now we are either committed to TIME or BYTE format, + * and we only expect a BYTE segment, e.g. following a seek */ + if (format == GST_FORMAT_BYTES) { + if (start > 0) { + offset = start; + start -= wav->datastart; + start = MAX (start, 0); + } + if (stop > 0) { + end_offset = stop; + stop -= wav->datastart; + stop = MAX (stop, 0); + } + if (wav->segment.format == GST_FORMAT_TIME) { + guint64 bps = wav->bps; + + /* operating in format TIME, so we can convert */ + if (!bps && wav->fact) + bps = + gst_util_uint64_scale_int (wav->datasize, wav->rate, wav->fact); + if (bps) { + if (start >= 0) + start = + uint64_ceiling_scale (start, GST_SECOND, (guint64) wav->bps); + if (stop >= 0) + stop = + uint64_ceiling_scale (stop, GST_SECOND, (guint64) wav->bps); + } + } + } else { + GST_DEBUG_OBJECT (wav, "unsupported segment format, ignoring"); + goto exit; + } + + /* accept upstream's notion of segment and distribute along */ + gst_segment_set_newsegment_full (&wav->segment, update, rate, arate, + wav->segment.format, start, stop, start); + /* also store the newsegment event for the streaming thread */ + if (wav->start_segment) + gst_event_unref (wav->start_segment); + wav->start_segment = + gst_event_new_new_segment_full (update, rate, arate, + wav->segment.format, start, stop, start); + GST_DEBUG_OBJECT (wav, "Pushing newseg update %d, rate %g, " + "applied rate %g, format %d, start %" G_GINT64_FORMAT ", " + "stop %" G_GINT64_FORMAT, update, rate, arate, wav->segment.format, + start, stop); + + /* stream leftover data in current segment */ + gst_wavparse_flush_data (wav); + /* and set up streaming thread for next one */ + wav->offset = offset; + wav->end_offset = end_offset; + if (wav->end_offset > 0) { + wav->dataleft = wav->end_offset - wav->offset; + } else { + /* infinity; upstream will EOS when done */ + wav->dataleft = G_MAXUINT64; + } + exit: + gst_event_unref (event); + break; + } + case GST_EVENT_EOS: + /* stream leftover data in current segment */ + gst_wavparse_flush_data (wav); + /* fall-through */ + case GST_EVENT_FLUSH_STOP: + gst_adapter_clear (wav->adapter); + wav->discont = TRUE; + /* fall-through */ + default: + ret = gst_pad_event_default (wav->sinkpad, event); + break; + } + + return ret; +} + #if 0 /* convert and query stuff */ static const GstFormat * @@ -2089,6 +2306,8 @@ gst_wavparse_pad_query (GstPad * pad, GstQuery * query) return FALSE; } + GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query)); + switch (GST_QUERY_TYPE (query)) { case GST_QUERY_POSITION: { @@ -2152,19 +2371,30 @@ gst_wavparse_pad_query (GstPad * pad, GstQuery * query) } case GST_QUERY_SEEKING:{ GstFormat fmt; + gboolean seekable = FALSE; gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL); - if (fmt == GST_FORMAT_TIME) { - gboolean seekable = TRUE; - - if ((wav->bps == 0) && !wav->fact) { - seekable = FALSE; - } else if (!gst_wavparse_calculate_duration (wav)) { - seekable = FALSE; - } - gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, - 0, wav->duration); + if (fmt == wav->segment.format) { res = TRUE; + if (wav->streaming) { + GstQuery *q; + + q = gst_query_new_seeking (GST_FORMAT_BYTES); + if ((res = gst_pad_peer_query (wav->sinkpad, q))) { + gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL); + GST_LOG_OBJECT (wav, "upstream BYTE seekable %d", seekable); + } + gst_query_unref (q); + } else { + GST_LOG_OBJECT (wav, "looping => seekable"); + seekable = TRUE; + res = TRUE; + } + } else if (fmt == GST_FORMAT_TIME) { + res = TRUE; + } + if (res) { + gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration); } break; }