From 62d5787bcda78bba5384732f9d25042d33af7923 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Feb 2009 13:00:58 +0100 Subject: [PATCH 1/9] rtpvrawpay: fail on interlaced video Detect and fail when trying to payload interlaced video. --- gst/rtp/gstrtpvrawpay.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) 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) { From af2e8f847017263d2f103f522187e4e6d76a6395 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Feb 2009 13:06:17 +0100 Subject: [PATCH 2/9] rtpvrawdepay: fail on interlaced video Fail on interlaced video until we support it. --- gst/rtp/gstrtpvrawdepay.c | 10 ++++++++++ 1 file changed, 10 insertions(+) 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"); From 474d9d7a9b9b32bfd66a558be468e7a5b588f992 Mon Sep 17 00:00:00 2001 From: Jan Smout Date: Thu, 26 Feb 2009 13:19:31 +0100 Subject: [PATCH 3/9] udp: fix gst_udp_set_loop_ttl() again Fix the gst_udp_set_loop_ttl() function that was commented out in a previous commit. See #573115. --- gst/udp/gstudpnetutils.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/gst/udp/gstudpnetutils.c b/gst/udp/gstudpnetutils.c index a1588caa6a..b1f864e394 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 = @@ -151,7 +156,6 @@ gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl) default: errno = EAFNOSUPPORT; } -#endif return ret; } From c7dd6a49026ca8818b80c138cdd511bd0266a416 Mon Sep 17 00:00:00 2001 From: Patrick Radizi Date: Thu, 26 Feb 2009 19:03:52 +0100 Subject: [PATCH 4/9] rtspsrc: add property to disable RTCP Some old servers don't like us doing RTCP and thus we need a property to disable it. See #573173. --- gst/rtsp/gstrtspsrc.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) 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) From 51200cad4108eb60ebd5f5a319ada463d40b455b Mon Sep 17 00:00:00 2001 From: Patrick Radizi Date: Thu, 26 Feb 2009 19:05:06 +0100 Subject: [PATCH 5/9] rtspsrc: add the .h file change too Add the .h file change for the new property. --- gst/rtsp/gstrtspsrc.h | 1 + 1 file changed, 1 insertion(+) 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; From ec5229d75f51308abf4858769026d7c3970eaf73 Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Thu, 26 Feb 2009 19:07:35 +0100 Subject: [PATCH 6/9] avidemux: fix SEEK event handling in push mode When in push mode we should not try to handle the SEEK event as there's no code to handle it properly. Propagate upstream. --- gst/avi/gstavidemux.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) 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"); } From 1846e0af0f55eb6931009242f23cfe0aaeb475f7 Mon Sep 17 00:00:00 2001 From: Edward Hervey Date: Fri, 27 Feb 2009 11:04:08 +0100 Subject: [PATCH 7/9] matroskademux: Remove gst_util_dump_mem() calls. --- gst/matroska/matroska-demux.c | 4 ---- 1 file changed, 4 deletions(-) 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); From 3310a540e3ad69d6ed87ddbafd9df22a5a7a7d89 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Fri, 27 Feb 2009 13:29:41 +0100 Subject: [PATCH 8/9] wavparse: Fix SEEK event handling in push mode, and SEEKABLY query handling Standard pull mode loop based SEEK handling fails in push mode, so convert the SEEK event appropriately and dispatch to upstream. Also cater for NEWSEGMENT event handling, and properly inform downstream and application of SEEKABLE capabilities, depending on scheduling mode and upstream. --- gst/wavparse/gstwavparse.c | 290 +++++++++++++++++++++++++++++++++---- 1 file changed, 260 insertions(+), 30 deletions(-) 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; } From b50452fc37a74cab50a44948efa944edd077af92 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Fri, 27 Feb 2009 11:17:50 -0800 Subject: [PATCH 9/9] rgvolume: ignore out-of-range peak values If the peak value is > 1 (and thus nonsensical) ignore it. Prevents rgvolume reducing volume to effectively silent on files with bogus peak values. --- gst/replaygain/gstrgvolume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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. */