summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorThomas Vander Stichele <thomas (at) apestaart (dot) org>2009-03-02 09:43:30 +0100
committerThomas Vander Stichele <thomas (at) apestaart (dot) org>2009-03-02 09:43:30 +0100
commit9f25f96155b246663a1f900624ccda4b9eafcded (patch)
tree029a4a4e8e96dc27e5f3ba38615bcfe9bee64455 /gst
parent13221762d09f8faacfbd682e68500ff22e6eb8ab (diff)
parent0083b9e40569db889500a3c1abd7ec3ac8876fee (diff)
Merge branch 'master' of ssh://thomasvs@git.freedesktop.org/git/gstreamer/gst-plugins-good
Diffstat (limited to 'gst')
-rw-r--r--gst/avi/gstavidemux.c34
-rw-r--r--gst/law/alaw-decode.c63
-rw-r--r--gst/law/alaw-encode.c22
-rw-r--r--gst/law/mulaw-decode.c58
-rw-r--r--gst/law/mulaw-encode.c22
-rw-r--r--gst/matroska/matroska-demux.c6
-rw-r--r--gst/matroska/matroska-mux.c3
-rw-r--r--gst/qtdemux/qtdemux.c5
-rw-r--r--gst/qtdemux/qtdemux_fourcc.h1
-rw-r--r--gst/replaygain/gstrgvolume.c14
-rw-r--r--gst/rtp/gstrtph264pay.c128
-rw-r--r--gst/rtp/gstrtpvrawdepay.c10
-rw-r--r--gst/rtp/gstrtpvrawpay.c39
-rw-r--r--gst/rtsp/gstrtspext.c17
-rw-r--r--gst/rtsp/gstrtspext.h1
-rw-r--r--gst/rtsp/gstrtspsrc.c90
-rw-r--r--gst/rtsp/gstrtspsrc.h1
-rw-r--r--gst/udp/gstudpnetutils.c16
-rw-r--r--gst/udp/gstudpsrc.c78
-rw-r--r--gst/wavparse/gstwavparse.c286
20 files changed, 705 insertions, 189 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 7a3166cf..adea05fd 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:
@@ -1707,7 +1711,7 @@ gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf)
goto next;
}
_dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (sub);
- dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
+ dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes);
GST_INFO_OBJECT (avi, "dmlh tag found:");
GST_INFO_OBJECT (avi, " totalframes: %u", dmlh.totalframes);
@@ -1799,10 +1803,10 @@ gst_avi_demux_parse_index (GstAviDemux * avi,
GstFormat format;
_entry = &((gst_riff_index_entry *) data)[i];
- entry.id = GUINT32_FROM_LE (_entry->id);
- entry.offset = GUINT32_FROM_LE (_entry->offset);
- entry.flags = GUINT32_FROM_LE (_entry->flags);
- entry.size = GUINT32_FROM_LE (_entry->size);
+ entry.id = GST_READ_UINT32_LE (&_entry->id);
+ entry.offset = GST_READ_UINT32_LE (&_entry->offset);
+ entry.flags = GST_READ_UINT32_LE (&_entry->flags);
+ entry.size = GST_READ_UINT32_LE (&_entry->size);
target = &entries[n];
if (entry.id == GST_RIFF_rec || entry.id == 0 ||
@@ -3599,7 +3603,7 @@ static GstBuffer *
gst_avi_demux_invert (avi_stream_context * stream, GstBuffer * buf)
{
GstStructure *s;
- gint y, h = stream->strf.vids->height;
+ gint y, w, h;
gint bpp, stride;
guint8 *tmp = NULL;
@@ -3616,7 +3620,14 @@ gst_avi_demux_invert (avi_stream_context * stream, GstBuffer * buf)
return buf;
}
- stride = stream->strf.vids->width * (bpp / 8);
+ if (stream->strf.vids == NULL) {
+ GST_WARNING ("Failed to retrieve vids for stream");
+ return buf;
+ }
+
+ h = stream->strf.vids->height;
+ w = stream->strf.vids->width;
+ stride = w * (bpp / 8);
buf = gst_buffer_make_writable (buf);
if (GST_BUFFER_SIZE (buf) < (stride * h)) {
@@ -4239,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 {
@@ -4250,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/law/alaw-decode.c b/gst/law/alaw-decode.c
index 9b990f7e..ac4c6df5 100644
--- a/gst/law/alaw-decode.c
+++ b/gst/law/alaw-decode.c
@@ -145,6 +145,57 @@ gst_alaw_dec_sink_setcaps (GstPad * pad, GstCaps * caps)
return ret;
}
+static GstCaps *
+gst_alaw_dec_getcaps (GstPad * pad)
+{
+ GstALawDec *alawdec;
+ GstPad *otherpad;
+ GstCaps *base_caps, *othercaps;
+
+ alawdec = GST_ALAW_DEC (GST_PAD_PARENT (pad));
+
+ base_caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+ if (pad == alawdec->srcpad) {
+ otherpad = alawdec->sinkpad;
+ } else {
+ otherpad = alawdec->srcpad;
+ }
+ othercaps = gst_pad_peer_get_caps (otherpad);
+ if (othercaps) {
+ GstStructure *structure;
+ const GValue *orate, *ochans;
+ const GValue *rate, *chans;
+ GValue irate = { 0 };
+ GValue ichans = { 0 };
+
+ if (gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps))
+ goto done;
+
+ structure = gst_caps_get_structure (othercaps, 0);
+ orate = gst_structure_get_value (structure, "rate");
+ ochans = gst_structure_get_value (structure, "channels");
+
+ structure = gst_caps_get_structure (base_caps, 0);
+ rate = gst_structure_get_value (structure, "rate");
+ chans = gst_structure_get_value (structure, "channels");
+
+ if (orate) {
+ gst_value_intersect (&irate, orate, rate);
+ gst_structure_set_value (structure, "rate", &irate);
+ }
+
+ if (ochans) {
+ gst_value_intersect (&ichans, ochans, chans);
+ gst_structure_set_value (structure, "channels", &ichans);
+ }
+
+ done:
+ gst_caps_unref (othercaps);
+ }
+ return base_caps;
+}
+
static void
gst_alaw_dec_base_init (gpointer klass)
{
@@ -177,6 +228,8 @@ gst_alaw_dec_init (GstALawDec * alawdec, GstALawDecClass * klass)
gst_pad_new_from_static_template (&alaw_dec_sink_factory, "sink");
gst_pad_set_setcaps_function (alawdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_alaw_dec_sink_setcaps));
+ gst_pad_set_getcaps_function (alawdec->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps));
gst_pad_set_chain_function (alawdec->sinkpad,
GST_DEBUG_FUNCPTR (gst_alaw_dec_chain));
gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->sinkpad);
@@ -184,6 +237,8 @@ gst_alaw_dec_init (GstALawDec * alawdec, GstALawDecClass * klass)
alawdec->srcpad =
gst_pad_new_from_static_template (&alaw_dec_src_factory, "src");
gst_pad_use_fixed_caps (alawdec->srcpad);
+ gst_pad_set_getcaps_function (alawdec->srcpad,
+ GST_DEBUG_FUNCPTR (gst_alaw_dec_getcaps));
gst_element_add_pad (GST_ELEMENT (alawdec), alawdec->srcpad);
}
@@ -238,14 +293,14 @@ gst_alaw_dec_chain (GstPad * pad, GstBuffer * buffer)
not_negotiated:
{
gst_buffer_unref (buffer);
- GST_ERROR_OBJECT (alawdec, "no format negotiated");
- ret = GST_FLOW_NOT_NEGOTIATED;
- return ret;
+ GST_WARNING_OBJECT (alawdec, "no input format set: not-negotiated");
+ return GST_FLOW_NOT_NEGOTIATED;
}
alloc_failed:
{
gst_buffer_unref (buffer);
- GST_ERROR_OBJECT (alawdec, "pad alloc failed");
+ GST_DEBUG_OBJECT (alawdec, "pad alloc failed, flow: %s",
+ gst_flow_get_name (ret));
return ret;
}
}
diff --git a/gst/law/alaw-encode.c b/gst/law/alaw-encode.c
index ba8587a2..b98d8e2e 100644
--- a/gst/law/alaw-encode.c
+++ b/gst/law/alaw-encode.c
@@ -318,8 +318,8 @@ gst_alaw_enc_getcaps (GstPad * pad)
GstStructure *structure;
const GValue *orate, *ochans;
const GValue *rate, *chans;
- GValue irate = { 0 }, ichans = {
- 0};
+ GValue irate = { 0 };
+ GValue ichans = { 0 };
if (gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps))
goto done;
@@ -327,22 +327,20 @@ gst_alaw_enc_getcaps (GstPad * pad)
structure = gst_caps_get_structure (othercaps, 0);
orate = gst_structure_get_value (structure, "rate");
ochans = gst_structure_get_value (structure, "channels");
- if (!orate || !ochans)
- goto done;
structure = gst_caps_get_structure (base_caps, 0);
rate = gst_structure_get_value (structure, "rate");
chans = gst_structure_get_value (structure, "channels");
- if (!rate || !chans)
- goto done;
- gst_value_intersect (&irate, orate, rate);
- gst_value_intersect (&ichans, ochans, chans);
+ if (orate) {
+ gst_value_intersect (&irate, orate, rate);
+ gst_structure_set_value (structure, "rate", &irate);
+ }
- /* Set the samplerate/channels on the to-be-returned caps */
- structure = gst_caps_get_structure (base_caps, 0);
- gst_structure_set_value (structure, "rate", &irate);
- gst_structure_set_value (structure, "channels", &ichans);
+ if (ochans) {
+ gst_value_intersect (&ichans, ochans, chans);
+ gst_structure_set_value (structure, "channels", &ichans);
+ }
done:
gst_caps_unref (othercaps);
diff --git a/gst/law/mulaw-decode.c b/gst/law/mulaw-decode.c
index 42b208f6..831ef0fa 100644
--- a/gst/law/mulaw-decode.c
+++ b/gst/law/mulaw-decode.c
@@ -88,6 +88,57 @@ mulawdec_sink_setcaps (GstPad * pad, GstCaps * caps)
return ret;
}
+static GstCaps *
+mulawdec_getcaps (GstPad * pad)
+{
+ GstMuLawDec *mulawdec;
+ GstPad *otherpad;
+ GstCaps *base_caps, *othercaps;
+
+ mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad));
+
+ base_caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+ if (pad == mulawdec->srcpad) {
+ otherpad = mulawdec->sinkpad;
+ } else {
+ otherpad = mulawdec->srcpad;
+ }
+ othercaps = gst_pad_peer_get_caps (otherpad);
+ if (othercaps) {
+ GstStructure *structure;
+ const GValue *orate, *ochans;
+ const GValue *rate, *chans;
+ GValue irate = { 0 };
+ GValue ichans = { 0 };
+
+ if (gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps))
+ goto done;
+
+ structure = gst_caps_get_structure (othercaps, 0);
+ orate = gst_structure_get_value (structure, "rate");
+ ochans = gst_structure_get_value (structure, "channels");
+
+ structure = gst_caps_get_structure (base_caps, 0);
+ rate = gst_structure_get_value (structure, "rate");
+ chans = gst_structure_get_value (structure, "channels");
+
+ if (orate) {
+ gst_value_intersect (&irate, orate, rate);
+ gst_structure_set_value (structure, "rate", &irate);
+ }
+
+ if (ochans) {
+ gst_value_intersect (&ichans, ochans, chans);
+ gst_structure_set_value (structure, "channels", &ichans);
+ }
+
+ done:
+ gst_caps_unref (othercaps);
+ }
+ return base_caps;
+}
+
GType
gst_mulawdec_get_type (void)
{
@@ -146,12 +197,14 @@ gst_mulawdec_init (GstMuLawDec * mulawdec)
mulawdec->sinkpad =
gst_pad_new_from_static_template (&mulaw_dec_sink_factory, "sink");
gst_pad_set_setcaps_function (mulawdec->sinkpad, mulawdec_sink_setcaps);
+ gst_pad_set_getcaps_function (mulawdec->sinkpad, mulawdec_getcaps);
gst_pad_set_chain_function (mulawdec->sinkpad, gst_mulawdec_chain);
gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->sinkpad);
mulawdec->srcpad =
gst_pad_new_from_static_template (&mulaw_dec_src_factory, "src");
gst_pad_use_fixed_caps (mulawdec->srcpad);
+ gst_pad_set_getcaps_function (mulawdec->srcpad, mulawdec_getcaps);
gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->srcpad);
}
@@ -205,13 +258,14 @@ gst_mulawdec_chain (GstPad * pad, GstBuffer * buffer)
/* ERRORS */
not_negotiated:
{
- GST_ERROR_OBJECT (mulawdec, "no format negotiated");
+ GST_WARNING_OBJECT (mulawdec, "no input format set: not-negotiated");
gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED;
}
alloc_failed:
{
- GST_ERROR_OBJECT (mulawdec, "pad alloc failed");
+ GST_DEBUG_OBJECT (mulawdec, "pad alloc failed, flow: %s",
+ gst_flow_get_name (ret));
gst_buffer_unref (buffer);
return ret;
}
diff --git a/gst/law/mulaw-encode.c b/gst/law/mulaw-encode.c
index f60e0b2e..022e96f1 100644
--- a/gst/law/mulaw-encode.c
+++ b/gst/law/mulaw-encode.c
@@ -75,8 +75,8 @@ mulawenc_getcaps (GstPad * pad)
GstStructure *structure;
const GValue *orate, *ochans;
const GValue *rate, *chans;
- GValue irate = { 0 }, ichans = {
- 0};
+ GValue irate = { 0 };
+ GValue ichans = { 0 };
if (gst_caps_is_empty (othercaps) || gst_caps_is_any (othercaps))
goto done;
@@ -84,22 +84,20 @@ mulawenc_getcaps (GstPad * pad)
structure = gst_caps_get_structure (othercaps, 0);
orate = gst_structure_get_value (structure, "rate");
ochans = gst_structure_get_value (structure, "channels");
- if (!orate || !ochans)
- goto done;
structure = gst_caps_get_structure (base_caps, 0);
rate = gst_structure_get_value (structure, "rate");
chans = gst_structure_get_value (structure, "channels");
- if (!rate || !chans)
- goto done;
- gst_value_intersect (&irate, orate, rate);
- gst_value_intersect (&ichans, ochans, chans);
+ if (orate) {
+ gst_value_intersect (&irate, orate, rate);
+ gst_structure_set_value (structure, "rate", &irate);
+ }
- /* Set the samplerate/channels on the to-be-returned caps */
- structure = gst_caps_get_structure (base_caps, 0);
- gst_structure_set_value (structure, "rate", &irate);
- gst_structure_set_value (structure, "channels", &ichans);
+ if (ochans) {
+ gst_value_intersect (&ichans, ochans, chans);
+ gst_structure_set_value (structure, "channels", &ichans);
+ }
done:
gst_caps_unref (othercaps);
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index 3c656c2c..50011cff 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -3864,7 +3864,7 @@ gst_matroska_demux_check_subtitle_buffer (GstElement * element,
GST_BUFFER_SIZE (newbuf) = strlen (utf8);
gst_buffer_copy_metadata (newbuf, *buf,
GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
- gst_buffer_unref (buf);
+ gst_buffer_unref (*buf);
*buf = newbuf;
return GST_FLOW_OK;
@@ -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/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c
index 746e3d19..1b958d69 100644
--- a/gst/matroska/matroska-mux.c
+++ b/gst/matroska/matroska-mux.c
@@ -650,7 +650,8 @@ gst_matroska_mux_video_pad_setcaps (GstPad * pad, GstCaps * caps)
gst_structure_get_int (structure, "height", &height);
videocontext->pixel_width = width;
videocontext->pixel_height = height;
- if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)) {
+ if (gst_structure_get_fraction (structure, "framerate", &fps_n, &fps_d)
+ && fps_n > 0) {
context->default_duration =
gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
GST_LOG_OBJECT (pad, "default duration = %" GST_TIME_FORMAT,
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c
index fe555a19..1cff4148 100644
--- a/gst/qtdemux/qtdemux.c
+++ b/gst/qtdemux/qtdemux.c
@@ -3109,11 +3109,11 @@ qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
index = QT_UINT32 ((guint8 *) stps->data + offset);
if (index > 0 && index <= stream->n_samples) {
samples[index - 1].keyframe = TRUE;
- offset += 4;
+ offset += 4;
+ }
}
}
}
- }
} else {
/* no stss, all samples are keyframes */
stream->all_keyframe = TRUE;
@@ -4184,6 +4184,7 @@ static const struct
FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
+ FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
qtdemux_tag_add_num}, {
diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h
index b4dabd73..cbf5b15f 100644
--- a/gst/qtdemux/qtdemux_fourcc.h
+++ b/gst/qtdemux/qtdemux_fourcc.h
@@ -90,6 +90,7 @@ G_BEGIN_DECLS
#define FOURCC__day GST_MAKE_FOURCC(0xa9,'d','a','y')
#define FOURCC__req GST_MAKE_FOURCC(0xa9,'r','e','q')
#define FOURCC__enc GST_MAKE_FOURCC(0xa9,'e','n','c')
+#define FOURCC__inf GST_MAKE_FOURCC(0xa9,'i','n','f')
#define FOURCC_cprt GST_MAKE_FOURCC('c','p','r','t')
#define FOURCC_gnre GST_MAKE_FOURCC('g','n','r','e')
#define FOURCC_disc GST_MAKE_FOURCC('d','i','s','c')
diff --git a/gst/replaygain/gstrgvolume.c b/gst/replaygain/gstrgvolume.c
index 41fe441d..cf5a914a 100644
--- a/gst/replaygain/gstrgvolume.c
+++ b/gst/replaygain/gstrgvolume.c
@@ -563,6 +563,20 @@ gst_rg_volume_tag_event (GstRgVolume * self, GstEvent * event)
has_album_peak = FALSE;
}
+ /* Clamp peaks >1.0. Float based decoders can produce spurious samples >1.0,
+ * cutting these files back to 1.0 should not cause any audible distortion.
+ * This is most often seen with Vorbis files. */
+ if (has_track_peak && self->track_peak > 1.) {
+ GST_DEBUG_OBJECT (self,
+ "clamping track peak %" PEAK_FORMAT " to 1.0", self->track_peak);
+ self->track_peak = 1.0;
+ }
+ if (has_album_peak && self->album_peak > 1.) {
+ GST_DEBUG_OBJECT (self,
+ "clamping album peak %" PEAK_FORMAT " to 1.0", self->album_peak);
+ self->album_peak = 1.0;
+ }
+
self->has_track_gain |= has_track_gain;
self->has_track_peak |= has_track_peak;
self->has_album_gain |= has_album_gain;
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
index f0cd9ee8..a788316b 100644
--- a/gst/rtp/gstrtph264pay.c
+++ b/gst/rtp/gstrtph264pay.c
@@ -449,15 +449,17 @@ is_nal_equal (const guint8 * nal1, const guint8 * nal2, guint len)
if (!remainder) {
return TRUE;
} else if (1 == remainder) {
- return (nal1[--len] == nal2[len]);
+ --len;
+ return (nal1[len] == nal2[len]);
} else { /* 2 or 3 */
if (remainder & 1) { /* -1 if 3 bytes left */
- if (nal1[--len] != nal2[len])
+ --len;
+ if (nal1[len] != nal2[len])
return FALSE;
}
/* last 2 bytes */
- return ((nal1[--len] == nal2[len]) /* -1 */
- &&(nal1[--len] == nal2[len])); /* -2 */
+ return ((nal1[len - 1] == nal2[len - 1]) /* -1 */
+ &&(nal1[len - 2] == nal2[len - 2])); /* -2 */
}
}
@@ -467,89 +469,71 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
{
guint8 *sps = NULL, *pps = NULL;
guint sps_len = 0, pps_len = 0;
+ guint8 header, type;
+ guint len;
/* default is no update */
*updated = FALSE;
- if (size <= 3) {
- GST_WARNING ("Encoded buffer len %u <= 3", size);
- } else {
- GST_DEBUG ("NAL payload len=%u", size);
+ GST_DEBUG ("NAL payload len=%u", size);
- /* loop through all NAL units and save the locations of any
- * SPS / PPS for later processing. Only the last seen SPS
- * or PPS will be considered */
- while (size > 5) {
- guint8 header, type;
- guint len;
+ len = size;
+ header = data[0];
+ type = header & 0x1f;
- len = next_start_code (data, size);
- header = data[0];
- type = header & 0x1f;
-
- /* keep sps & pps separately so that we can update either one
- * independently */
- if (SPS_TYPE_ID == type) {
- /* encode the entire SPS NAL in base64 */
- GST_DEBUG ("Found SPS %x %x %x Len=%u", (header >> 7),
- (header >> 5) & 3, type, len);
-
- sps = data;
- sps_len = len;
- } else if (PPS_TYPE_ID == type) {
- /* encoder the entire PPS NAL in base64 */
- GST_DEBUG ("Found PPS %x %x %x Len = %u",
- (header >> 7), (header >> 5) & 3, type, len);
-
- pps = data;
- pps_len = len;
- } else {
- GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
- (header >> 5) & 3, type, len);
- }
+ /* keep sps & pps separately so that we can update either one
+ * independently */
+ if (SPS_TYPE_ID == type) {
+ /* encode the entire SPS NAL in base64 */
+ GST_DEBUG ("Found SPS %x %x %x Len=%u", (header >> 7),
+ (header >> 5) & 3, type, len);
- /* end of loop */
- if (len >= size - 4) {
- break;
- }
+ sps = data;
+ sps_len = len;
+ } else if (PPS_TYPE_ID == type) {
+ /* encoder the entire PPS NAL in base64 */
+ GST_DEBUG ("Found PPS %x %x %x Len = %u",
+ (header >> 7), (header >> 5) & 3, type, len);
- /* next NAL start */
- data += len + 4;
- size -= len + 4;
- }
+ pps = data;
+ pps_len = len;
+ } else {
+ GST_DEBUG ("NAL: %x %x %x Len = %u", (header >> 7),
+ (header >> 5) & 3, type, len);
+ }
- /* If we encountered an SPS and/or a PPS, check if it's the
- * same as the one we have. If not, update our version and
- * set *updated to TRUE
- */
- if (sps_len > 0) {
- if ((payloader->sps_len != sps_len)
- || !is_nal_equal (payloader->sps, sps, sps_len)) {
- payloader->profile = (sps[1] << 16) + (sps[2] << 8) + sps[3];
- GST_DEBUG ("Profile level IDC = %06x", payloader->profile);
+ /* If we encountered an SPS and/or a PPS, check if it's the
+ * same as the one we have. If not, update our version and
+ * set *updated to TRUE
+ */
+ if (sps_len > 0) {
+ if ((payloader->sps_len != sps_len)
+ || !is_nal_equal (payloader->sps, sps, sps_len)) {
+ payloader->profile = (sps[1] << 16) + (sps[2] << 8) + sps[3];
- if (payloader->sps_len)
- g_free (payloader->sps);
+ GST_DEBUG ("Profile level IDC = %06x", payloader->profile);
- payloader->sps = sps_len ? g_new (guint8, sps_len) : NULL;
- memcpy (payloader->sps, sps, sps_len);
- payloader->sps_len = sps_len;
- *updated = TRUE;
- }
+ if (payloader->sps_len)
+ g_free (payloader->sps);
+
+ payloader->sps = sps_len ? g_new (guint8, sps_len) : NULL;
+ memcpy (payloader->sps, sps, sps_len);
+ payloader->sps_len = sps_len;
+ *updated = TRUE;
}
+ }
- if (pps_len > 0) {
- if ((payloader->pps_len != pps_len)
- || !is_nal_equal (payloader->pps, pps, pps_len)) {
- if (payloader->pps_len)
- g_free (payloader->pps);
+ if (pps_len > 0) {
+ if ((payloader->pps_len != pps_len)
+ || !is_nal_equal (payloader->pps, pps, pps_len)) {
+ if (payloader->pps_len)
+ g_free (payloader->pps);
- payloader->pps = pps_len ? g_new (guint8, pps_len) : NULL;
- memcpy (payloader->pps, pps, pps_len);
- payloader->pps_len = pps_len;
- *updated = TRUE;
- }
+ payloader->pps = pps_len ? g_new (guint8, pps_len) : NULL;
+ memcpy (payloader->pps, pps, pps_len);
+ payloader->pps_len = pps_len;
+ *updated = TRUE;
}
}
}
diff --git a/gst/rtp/gstrtpvrawdepay.c b/gst/rtp/gstrtpvrawdepay.c
index 35e68a3e..3f599f5d 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 19c14c2b..0f0ef7e8 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/gstrtspext.c b/gst/rtsp/gstrtspext.c
index 0ad81b56..a3216794 100644
--- a/gst/rtsp/gstrtspext.c
+++ b/gst/rtsp/gstrtspext.c
@@ -247,3 +247,20 @@ gst_rtsp_ext_list_connect (GstRTSPExtensionList * ext,
g_signal_connect (elem, detailed_signal, c_handler, data);
}
}
+
+GstRTSPResult
+gst_rtsp_ext_list_receive_request (GstRTSPExtensionList * ext,
+ GstRTSPMessage * req)
+{
+ GList *walk;
+ GstRTSPResult res = GST_RTSP_ENOTIMPL;
+
+ for (walk = ext->extensions; walk; walk = g_list_next (walk)) {
+ GstRTSPExtension *elem = (GstRTSPExtension *) walk->data;
+
+ res = gst_rtsp_extension_receive_request (elem, req);
+ if (res != GST_RTSP_ENOTIMPL)
+ break;
+ }
+ return res;
+}
diff --git a/gst/rtsp/gstrtspext.h b/gst/rtsp/gstrtspext.h
index fa7f6892..f30b302f 100644
--- a/gst/rtsp/gstrtspext.h
+++ b/gst/rtsp/gstrtspext.h
@@ -76,6 +76,7 @@ GstRTSPResult gst_rtsp_ext_list_stream_select (GstRTSPExtensionList *ext, Gs
void gst_rtsp_ext_list_connect (GstRTSPExtensionList *ext,
const gchar *detailed_signal, GCallback c_handler,
gpointer data);
+GstRTSPResult gst_rtsp_ext_list_receive_request (GstRTSPExtensionList *ext, GstRTSPMessage *req);
G_END_DECLS
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
index 02970c42..7c5ef8a6 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);
@@ -2536,20 +2557,25 @@ gst_rtspsrc_handle_request (GstRTSPSrc * src, GstRTSPMessage * request)
if (src->debug)
gst_rtsp_message_dump (request);
- res =
- gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK",
- request);
- if (res < 0)
- goto send_error;
+ res = gst_rtsp_ext_list_receive_request (src->extensions, request);
+
+ if (res == GST_RTSP_ENOTIMPL) {
+ /* default implementation, send OK */
+ res =
+ gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK, "OK",
+ request);
+ if (res < 0)
+ goto send_error;
- GST_DEBUG_OBJECT (src, "replying with OK");
+ GST_DEBUG_OBJECT (src, "replying with OK");
- if (src->debug)
- gst_rtsp_message_dump (&response);
+ if (src->debug)
+ gst_rtsp_message_dump (&response);
- res = gst_rtspsrc_connection_send (src, &response, NULL);
- if (res < 0)
- goto send_error;
+ res = gst_rtspsrc_connection_send (src, &response, NULL);
+ if (res < 0)
+ goto send_error;
+ }
return GST_RTSP_OK;
@@ -3785,7 +3811,8 @@ failed:
}
static GstRTSPResult
-gst_rtspsrc_prepare_transports (GstRTSPStream * stream, gchar ** transports)
+gst_rtspsrc_prepare_transports (GstRTSPStream * stream, gchar ** transports,
+ gint orig_rtpport, gint orig_rtcpport)
{
GstRTSPSrc *src;
gint nr_udp, nr_int;
@@ -3814,8 +3841,13 @@ gst_rtspsrc_prepare_transports (GstRTSPStream * stream, gchar ** transports)
goto done;
if (nr_udp > 0) {
- if (!gst_rtspsrc_alloc_udp_ports (stream, &rtpport, &rtcpport))
- goto failed;
+ if (!orig_rtpport || !orig_rtcpport) {
+ if (!gst_rtspsrc_alloc_udp_ports (stream, &rtpport, &rtcpport))
+ goto failed;
+ } else {
+ rtpport = orig_rtpport;
+ rtcpport = orig_rtcpport;
+ }
}
str = g_string_new ("");
@@ -3875,6 +3907,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
GstRTSPStream *stream = NULL;
GstRTSPLowerTrans protocols;
GstRTSPStatusCode code;
+ gint rtpport, rtcpport;
/* we initially allow all configured lower transports. based on the URL
* transports and the replies from the server we narrow them down. */
@@ -3887,9 +3920,11 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
src->free_channel = 0;
src->interleaved = FALSE;
src->need_activate = FALSE;
+ rtpport = rtcpport = 0;
for (walk = src->streams; walk; walk = g_list_next (walk)) {
gchar *transports;
+ gint retry = 0;
stream = (GstRTSPStream *) walk->data;
@@ -3930,6 +3965,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
GST_DEBUG_OBJECT (src, "doing setup of stream %p with %s", stream,
stream->setup_url);
+ retry:
/* create a string with all the transports */
res = gst_rtspsrc_create_transports_string (src, protocols, &transports);
if (res < 0)
@@ -3939,7 +3975,8 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
/* replace placeholders with real values, this function will optionally
* allocate UDP ports and other info needed to execute the setup request */
- res = gst_rtspsrc_prepare_transports (stream, &transports);
+ res = gst_rtspsrc_prepare_transports (stream, &transports,
+ retry > 0 ? rtpport : 0, retry > 0 ? rtcpport : 0);
if (res < 0)
goto setup_transport_failed;
@@ -3966,8 +4003,17 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
case GST_RTSP_STS_UNSUPPORTED_TRANSPORT:
gst_rtsp_message_unset (&request);
gst_rtsp_message_unset (&response);
- /* cleanup of leftover transport and move to the next stream */
+ /* cleanup of leftover transport */
gst_rtspsrc_stream_free_udp (stream);
+ /* MS WMServer RTSP MUST use same UDP pair in all SETUP requests;
+ * we might be in this case */
+ if (stream->container && rtpport && rtcpport && !retry) {
+ GST_DEBUG_OBJECT (src, "retrying with original port pair %u-%u",
+ rtpport, rtcpport);
+ retry++;
+ goto retry;
+ }
+ /* give up on this stream and move to the next stream */
continue;
default:
/* cleanup of leftover transport and move to the next stream */
@@ -4024,13 +4070,17 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src)
break;
}
- if (!stream->container || !src->interleaved) {
+ if (!stream->container || (!src->interleaved && !retry)) {
/* now configure the stream with the selected transport */
if (!gst_rtspsrc_stream_configure_transport (stream, &transport)) {
GST_DEBUG_OBJECT (src,
"could not configure stream %p transport, skipping stream",
stream);
goto next;
+ } else if (stream->udpsrc[0] && stream->udpsrc[1]) {
+ /* retain the first allocated UDP port pair */
+ g_object_get (G_OBJECT (stream->udpsrc[0]), "port", &rtpport, NULL);
+ g_object_get (G_OBJECT (stream->udpsrc[1]), "port", &rtcpport, NULL);
}
}
/* we need to activate at least one streams when we detect activity */
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
index 95dd9869..40a368c6 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 a1588caa..5fa7593a 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 =
@@ -149,9 +154,12 @@ gst_udp_set_loop_ttl (int sockfd, gboolean loop, int ttl)
break;
}
default:
+#ifdef G_OS_WIN32
+ WSASetLastError (WSAEAFNOSUPPORT);
+#else
errno = EAFNOSUPPORT;
- }
#endif
+ }
return ret;
}
diff --git a/gst/udp/gstudpsrc.c b/gst/udp/gstudpsrc.c
index bcdbc359..8d92241e 100644
--- a/gst/udp/gstudpsrc.c
+++ b/gst/udp/gstudpsrc.c
@@ -357,13 +357,50 @@ gst_udpsrc_getcaps (GstBaseSrc * src)
return gst_caps_new_any ();
}
+/* read a message from the error queue */
+static void
+clear_error (GstUDPSrc * udpsrc)
+{
+#if defined (MSG_ERRQUEUE)
+ struct msghdr cmsg;
+ char cbuf[128];
+ char msgbuf[CMSG_SPACE (128)];
+ struct iovec iov;
+
+ /* Flush ERRORS from fd so next poll will not return at once */
+ /* No need for address : We look for local error */
+ cmsg.msg_name = NULL;
+ cmsg.msg_namelen = 0;
+
+ /* IOV */
+ memset (&cbuf, 0, sizeof (cbuf));
+ iov.iov_base = cbuf;
+ iov.iov_len = sizeof (cbuf);
+ cmsg.msg_iov = &iov;
+ cmsg.msg_iovlen = 1;
+
+ /* msg_control */
+ memset (&msgbuf, 0, sizeof (msgbuf));
+ cmsg.msg_control = &msgbuf;
+ cmsg.msg_controllen = sizeof (msgbuf);
+
+ recvmsg (udpsrc->sock.fd, &cmsg, MSG_ERRQUEUE);
+#endif
+}
+
static GstFlowReturn
gst_udpsrc_create (GstPushSrc * psrc, GstBuffer ** buf)
{
GstUDPSrc *udpsrc;
GstNetBuffer *outbuf;
- struct sockaddr_storage tmpaddr;
- socklen_t len;
+ union gst_sockaddr
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+ struct sockaddr_in6 sa_in6;
+ struct sockaddr_storage sa_stor;
+ } sa;
+ socklen_t slen;
guint8 *pktdata;
gint pktsize;
#ifdef G_OS_UNIX
@@ -434,8 +471,10 @@ retry:
* woken up by activity on the socket but it was not a read. We know someone
* will also do something with the socket so that we don't go into an infinite
* loop in the select(). */
- if (G_UNLIKELY (!readsize))
+ if (G_UNLIKELY (!readsize)) {
+ clear_error (udpsrc);
goto retry;
+ }
no_select:
GST_LOG_OBJECT (udpsrc, "ioctl says %d bytes available", (int) readsize);
@@ -444,13 +483,13 @@ no_select:
pktsize = readsize;
while (TRUE) {
- len = sizeof (struct sockaddr);
+ slen = sizeof (sa);
#ifdef G_OS_WIN32
- ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize,
+ ret = recvfrom (udpsrc->sock.fd, (char *) pktdata, pktsize, 0, &sa.sa,
+ &slen);
#else
- ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize,
+ ret = recvfrom (udpsrc->sock.fd, pktdata, pktsize, 0, &sa.sa, &slen);
#endif
- 0, (struct sockaddr *) &tmpaddr, &len);
if (G_UNLIKELY (ret < 0)) {
#ifdef G_OS_WIN32
/* WSAECONNRESET for a UDP socket means that a packet sent with udpsink
@@ -486,22 +525,19 @@ no_select:
GST_BUFFER_DATA (outbuf) = pktdata;
GST_BUFFER_SIZE (outbuf) = ret;
- switch (tmpaddr.ss_family) {
+ switch (sa.sa.sa_family) {
case AF_INET:
{
- gst_netaddress_set_ip4_address (&outbuf->from,
- ((struct sockaddr_in *) &tmpaddr)->sin_addr.s_addr,
- ((struct sockaddr_in *) &tmpaddr)->sin_port);
+ gst_netaddress_set_ip4_address (&outbuf->from, sa.sa_in.sin_addr.s_addr,
+ sa.sa_in.sin_port);
}
break;
case AF_INET6:
{
guint8 ip6[16];
- memcpy (ip6, &((struct sockaddr_in6 *) &tmpaddr)->sin6_addr,
- sizeof (ip6));
- gst_netaddress_set_ip6_address (&outbuf->from, ip6,
- ((struct sockaddr_in *) &tmpaddr)->sin_port);
+ memcpy (ip6, &sa.sa_in6.sin6_addr, sizeof (ip6));
+ gst_netaddress_set_ip6_address (&outbuf->from, ip6, sa.sa_in6.sin6_port);
}
break;
default:
@@ -730,6 +766,7 @@ static gboolean
gst_udpsrc_start (GstBaseSrc * bsrc)
{
guint bc_val;
+ guint err_val;
gint reuse;
int port;
GstUDPSrc *src;
@@ -821,6 +858,17 @@ gst_udpsrc_start (GstBaseSrc * bsrc)
g_strerror (errno), errno));
}
+ /* Accept ERRQUEUE to get and flush icmp errors */
+ err_val = 1;
+#if defined (IP_RECVERR)
+ if ((ret = setsockopt (src->sock.fd, IPPROTO_IP, IP_RECVERR, &err_val,
+ sizeof (err_val))) < 0) {
+ GST_ELEMENT_WARNING (src, RESOURCE, SETTINGS, (NULL),
+ ("could not configure socket for IP_RECVERR %d: %s (%d)", ret,
+ g_strerror (errno), errno));
+ }
+#endif
+
if (src->auto_multicast && gst_udp_is_multicast (&src->myaddr)) {
GST_DEBUG_OBJECT (src, "joining multicast group %s", src->multi_group);
ret = gst_udp_join_group (src->sock.fd, &src->myaddr);
diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c
index 266c430f..c8e7c756 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,20 +2371,31 @@ 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 (fmt == wav->segment.format) {
+ res = TRUE;
+ if (wav->streaming) {
+ GstQuery *q;
- if ((wav->bps == 0) && !wav->fact) {
- seekable = FALSE;
- } else if (!gst_wavparse_calculate_duration (wav)) {
- seekable = FALSE;
+ 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;
}
- gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
- 0, wav->duration);
+ } else if (fmt == GST_FORMAT_TIME) {
res = TRUE;
}
+ if (res) {
+ gst_query_set_seeking (query, fmt, seekable, 0, wav->segment.duration);
+ }
break;
}
default: