aboutsummaryrefslogtreecommitdiff
path: root/gst
diff options
context:
space:
mode:
Diffstat (limited to 'gst')
-rw-r--r--gst/avi/gstavidemux.c44
-rw-r--r--gst/avi/gstavidemux.h4
-rw-r--r--gst/flv/gstflvdemux.c128
-rw-r--r--gst/flv/gstflvdemux.h3
-rw-r--r--gst/isomp4/fourcc.h5
-rw-r--r--gst/isomp4/qtdemux.c189
-rw-r--r--gst/isomp4/qtdemux.h3
-rw-r--r--gst/matroska/matroska-demux.c48
-rw-r--r--gst/matroska/matroska-demux.h3
-rw-r--r--gst/matroska/matroska-ids.h1
-rw-r--r--gst/matroska/matroska-parse.c1
-rw-r--r--gst/matroska/matroska-read-common.c4
-rw-r--r--gst/multipart/multipartdemux.c42
-rw-r--r--gst/multipart/multipartdemux.h4
-rw-r--r--gst/rtp/gstrtpdvpay.c17
-rw-r--r--gst/rtp/gstrtpg729pay.c15
-rw-r--r--gst/rtp/gstrtpgstpay.c9
-rw-r--r--gst/rtp/gstrtph263pay.c21
-rw-r--r--gst/rtp/gstrtph264depay.c6
-rw-r--r--gst/rtp/gstrtph264pay.c114
-rw-r--r--gst/rtp/gstrtph264pay.h5
-rw-r--r--gst/rtp/gstrtpj2kpay.c4
-rw-r--r--gst/rtp/gstrtpjpegpay.c17
-rw-r--r--gst/rtp/gstrtpmp4gpay.c7
-rw-r--r--gst/rtp/gstrtpmp4gpay.h1
-rw-r--r--gst/rtp/gstrtpmp4vpay.c10
-rw-r--r--gst/rtp/gstrtptheoradepay.c20
-rw-r--r--gst/rtp/gstrtpvp8depay.c21
-rw-r--r--gst/rtp/gstrtpvp8pay.c68
-rw-r--r--gst/rtp/gstrtpvrawpay.c146
-rw-r--r--gst/rtp/gstrtpvrawpay.h8
-rw-r--r--gst/rtsp/gstrtspsrc.c189
-rw-r--r--gst/rtsp/gstrtspsrc.h2
-rw-r--r--gst/udp/gstdynudpsink.c20
-rw-r--r--gst/udp/gstmultiudpsink.c22
-rw-r--r--gst/udp/gstmultiudpsink.h1
-rw-r--r--gst/videobox/gstvideobox.c21
-rw-r--r--gst/wavparse/gstwavparse.c10
38 files changed, 848 insertions, 385 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 22d3dbb8..c84ffce8 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -196,6 +196,7 @@ gst_avi_demux_init (GstAviDemux * avi)
gst_element_add_pad (GST_ELEMENT_CAST (avi), avi->sinkpad);
avi->adapter = gst_adapter_new ();
+ avi->flowcombiner = gst_flow_combiner_new ();
gst_avi_demux_reset (avi);
@@ -210,6 +211,7 @@ gst_avi_demux_finalize (GObject * object)
GST_DEBUG ("AVI: finalize");
g_object_unref (avi->adapter);
+ gst_flow_combiner_free (avi->flowcombiner);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -232,6 +234,7 @@ gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
if (stream->exposed) {
gst_pad_set_active (stream->pad, FALSE);
gst_element_remove_pad (GST_ELEMENT_CAST (avi), stream->pad);
+ gst_flow_combiner_remove_pad (avi->flowcombiner, stream->pad);
} else
gst_object_unref (stream->pad);
}
@@ -898,7 +901,6 @@ gst_avi_demux_handle_sink_event (GstPad * pad, GstObject * parent,
gst_adapter_clear (avi->adapter);
avi->have_eos = FALSE;
for (i = 0; i < avi->num_streams; i++) {
- avi->stream[i].last_flow = GST_FLOW_OK;
avi->stream[i].discont = TRUE;
}
/* fall through to default case so that the event gets passed downstream */
@@ -1886,6 +1888,7 @@ gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force)
if (force || stream->idx_n != 0) {
GST_LOG_OBJECT (avi, "Adding pad %s", GST_PAD_NAME (stream->pad));
gst_element_add_pad ((GstElement *) avi, stream->pad);
+ gst_flow_combiner_add_pad (avi->flowcombiner, stream->pad);
#if 0
if (avi->element_index)
@@ -2404,7 +2407,6 @@ gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
stream->current_entry = -1;
stream->current_total = 0;
- stream->last_flow = GST_FLOW_OK;
stream->discont = TRUE;
stream->total_bytes = 0;
@@ -4638,7 +4640,6 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
/* reset the last flow and mark discont, seek is always DISCONT */
for (i = 0; i < avi->num_streams; i++) {
GST_DEBUG_OBJECT (avi, "marking DISCONT");
- avi->stream[i].last_flow = GST_FLOW_OK;
avi->stream[i].discont = TRUE;
}
GST_PAD_STREAM_UNLOCK (avi->sinkpad);
@@ -5003,37 +5004,11 @@ static GstFlowReturn
gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
GstFlowReturn ret)
{
- guint i;
- gboolean unexpected = FALSE, not_linked = TRUE;
-
- /* store the value */
- stream->last_flow = ret;
-
- /* any other error that is not-linked or eos can be returned right away */
- if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
- goto done;
-
- /* only return NOT_LINKED if all other pads returned NOT_LINKED */
- for (i = 0; i < avi->num_streams; i++) {
- GstAviStream *ostream = &avi->stream[i];
-
- ret = ostream->last_flow;
- /* no unexpected or unlinked, return */
- if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
- goto done;
+ GST_LOG_OBJECT (avi, "Stream %s:%s flow return: %s",
+ GST_DEBUG_PAD_NAME (stream->pad), gst_flow_get_name (ret));
+ ret = gst_flow_combiner_update_flow (avi->flowcombiner, ret);
+ GST_LOG_OBJECT (avi, "combined to return %s", gst_flow_get_name (ret));
- /* we check to see if we have at least 1 unexpected or all unlinked */
- unexpected |= (ret == GST_FLOW_EOS);
- not_linked &= (ret == GST_FLOW_NOT_LINKED);
- }
- /* when we get here, we all have unlinked or unexpected */
- if (not_linked)
- ret = GST_FLOW_NOT_LINKED;
- else if (unexpected)
- ret = GST_FLOW_EOS;
-done:
- GST_LOG_OBJECT (avi, "combined %s to return %s",
- gst_flow_get_name (stream->last_flow), gst_flow_get_name (ret));
return ret;
}
@@ -5092,7 +5067,6 @@ gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
&stream->current_timestamp, &stream->current_ts_end,
&stream->current_offset, &stream->current_offset_end);
/* and MARK discont for this stream */
- stream->last_flow = GST_FLOW_OK;
stream->discont = TRUE;
GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
@@ -5134,7 +5108,7 @@ gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
stream = &avi->stream[i];
/* ignore streams that finished */
- if (stream->last_flow == GST_FLOW_EOS)
+ if (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)
continue;
position = stream->current_timestamp;
diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h
index 0e8786fb..fd2af507 100644
--- a/gst/avi/gstavidemux.h
+++ b/gst/avi/gstavidemux.h
@@ -27,6 +27,7 @@
#include "gst/riff/riff-ids.h"
#include "gst/riff/riff-read.h"
#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
G_BEGIN_DECLS
@@ -90,7 +91,6 @@ typedef struct {
guint64 current_offset;
guint64 current_offset_end;
- GstFlowReturn last_flow;
gboolean discont;
/* stream length */
@@ -165,6 +165,8 @@ typedef struct _GstAviDemux {
guint main_stream; /* used for seeking */
+ GstFlowCombiner *flowcombiner;
+
gboolean have_group_id;
guint group_id;
diff --git a/gst/flv/gstflvdemux.c b/gst/flv/gstflvdemux.c
index 212d18a3..0af779ca 100644
--- a/gst/flv/gstflvdemux.c
+++ b/gst/flv/gstflvdemux.c
@@ -885,10 +885,11 @@ gst_flv_demux_push_tags (GstFlvDemux * demux)
}
}
-static void
+static gboolean
gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
guint32 * last, GstClockTime * offset)
{
+ gboolean ret = FALSE;
gint32 dpts = pts - *last;
if (!discont && ABS (dpts) >= RESYNC_THRESHOLD) {
/* Theoretically, we should use substract the duration of the last buffer,
@@ -898,8 +899,12 @@ gst_flv_demux_update_resync (GstFlvDemux * demux, guint32 pts, gboolean discont,
GST_WARNING_OBJECT (demux,
"Large pts gap (%" G_GINT32_FORMAT " ms), assuming resync, offset now %"
GST_TIME_FORMAT "", dpts, GST_TIME_ARGS (*offset));
+
+ ret = TRUE;
}
*last = pts;
+
+ return ret;
}
static GstFlowReturn
@@ -1031,6 +1036,7 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
/* We need to set caps before adding */
gst_element_add_pad (GST_ELEMENT (demux),
gst_object_ref (demux->audio_pad));
+ gst_flow_combiner_add_pad (demux->flowcombiner, demux->audio_pad);
/* We only emit no more pads when we have audio and video. Indeed we can
* not trust the FLV header to tell us if there will be only audio or
@@ -1098,8 +1104,10 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
}
/* detect (and deem to be resyncs) large pts gaps */
- gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
- &demux->last_audio_pts, &demux->audio_time_offset);
+ if (gst_flv_demux_update_resync (demux, pts, demux->audio_need_discont,
+ &demux->last_audio_pts, &demux->audio_time_offset)) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
/* Fill buffer with data */
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->audio_time_offset;
@@ -1170,27 +1178,20 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
/* Push downstream */
ret = gst_pad_push (demux->audio_pad, outbuf);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
- demux->segment.position > demux->segment.stop) {
- /* In reverse playback we can get a GST_FLOW_EOS when
- * we are at the end of the segment, so we just need to jump
- * back to the previous section. */
- GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
- demux->audio_done = TRUE;
- ret = GST_FLOW_OK;
- } else {
- if (ret == GST_FLOW_NOT_LINKED) {
- demux->audio_linked = FALSE;
- } else
- GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
- " bytes audio buffer: %s", demux->tag_data_size,
- gst_flow_get_name (ret));
- goto beach;
- }
+
+ if (G_UNLIKELY (ret != GST_FLOW_OK) &&
+ demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
+ demux->segment.position > demux->segment.stop) {
+ /* In reverse playback we can get a GST_FLOW_EOS when
+ * we are at the end of the segment, so we just need to jump
+ * back to the previous section. */
+ GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
+ demux->audio_done = TRUE;
+ ret = GST_FLOW_OK;
+ goto beach;
}
- demux->audio_linked = TRUE;
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
beach:
gst_buffer_unmap (buffer, &map);
@@ -1420,6 +1421,7 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
/* We need to set caps before adding */
gst_element_add_pad (GST_ELEMENT (demux),
gst_object_ref (demux->video_pad));
+ gst_flow_combiner_add_pad (demux->flowcombiner, demux->video_pad);
/* We only emit no more pads when we have audio and video. Indeed we can
* not trust the FLV header to tell us if there will be only audio or
@@ -1489,8 +1491,10 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
}
/* detect (and deem to be resyncs) large pts gaps */
- gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
- &demux->last_video_pts, &demux->video_time_offset);
+ if (gst_flv_demux_update_resync (demux, pts, demux->video_need_discont,
+ &demux->last_video_pts, &demux->video_time_offset)) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC);
+ }
/* Fill buffer with data */
GST_BUFFER_TIMESTAMP (outbuf) = pts * GST_MSECOND + demux->video_time_offset;
@@ -1564,27 +1568,19 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
/* Push downstream */
ret = gst_pad_push (demux->video_pad, outbuf);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- if (demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
- demux->segment.position > demux->segment.stop) {
- /* In reverse playback we can get a GST_FLOW_EOS when
- * we are at the end of the segment, so we just need to jump
- * back to the previous section. */
- GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
- demux->video_done = TRUE;
- ret = GST_FLOW_OK;
- } else {
- if (ret == GST_FLOW_NOT_LINKED)
- demux->video_linked = FALSE;
- else
- GST_WARNING_OBJECT (demux, "failed pushing a %" G_GUINT64_FORMAT
- " bytes video buffer: %s", demux->tag_data_size,
- gst_flow_get_name (ret));
- goto beach;
- }
+ if (G_UNLIKELY (ret != GST_FLOW_OK) &&
+ demux->segment.rate < 0.0 && ret == GST_FLOW_EOS &&
+ demux->segment.position > demux->segment.stop) {
+ /* In reverse playback we can get a GST_FLOW_EOS when
+ * we are at the end of the segment, so we just need to jump
+ * back to the previous section. */
+ GST_DEBUG_OBJECT (demux, "downstream has reached end of segment");
+ demux->video_done = TRUE;
+ ret = GST_FLOW_OK;
+ goto beach;
}
- demux->video_linked = TRUE;
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
beach:
gst_buffer_unmap (buffer, &map);
@@ -1811,10 +1807,6 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
demux->audio_need_discont = TRUE;
demux->video_need_discont = TRUE;
- /* By default we consider them as linked */
- demux->audio_linked = TRUE;
- demux->video_linked = TRUE;
-
demux->has_audio = FALSE;
demux->has_video = FALSE;
demux->push_tags = FALSE;
@@ -1862,12 +1854,14 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
}
if (demux->audio_pad) {
+ gst_flow_combiner_remove_pad (demux->flowcombiner, demux->audio_pad);
gst_element_remove_pad (GST_ELEMENT (demux), demux->audio_pad);
gst_object_unref (demux->audio_pad);
demux->audio_pad = NULL;
}
if (demux->video_pad) {
+ gst_flow_combiner_remove_pad (demux->flowcombiner, demux->video_pad);
gst_element_remove_pad (GST_ELEMENT (demux), demux->video_pad);
gst_object_unref (demux->video_pad);
demux->video_pad = NULL;
@@ -1947,13 +1941,8 @@ gst_flv_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
parse:
if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- if (ret == GST_FLOW_NOT_LINKED && (demux->audio_linked
- || demux->video_linked)) {
- ret = GST_FLOW_OK;
- } else {
- GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
- goto beach;
- }
+ GST_DEBUG_OBJECT (demux, "got flow return %s", gst_flow_get_name (ret));
+ goto beach;
}
if (G_UNLIKELY (demux->flushing)) {
@@ -2127,13 +2116,6 @@ parse:
}
beach:
- if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
- /* If either audio or video is linked we return GST_FLOW_OK */
- if (demux->audio_linked || demux->video_linked) {
- ret = GST_FLOW_OK;
- }
- }
-
return ret;
/* ERRORS */
@@ -2242,13 +2224,8 @@ gst_flv_demux_pull_tag (GstPad * pad, GstFlvDemux * demux)
demux->state = FLV_STATE_TAG_TYPE;
if (G_UNLIKELY (ret == GST_FLOW_NOT_LINKED)) {
- /* If either audio or video is linked we return GST_FLOW_OK */
- if (demux->audio_linked || demux->video_linked) {
- ret = GST_FLOW_OK;
- } else {
- GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
- "neither video nor audio are linked");
- }
+ GST_WARNING_OBJECT (demux, "parsing this tag returned not-linked and "
+ "neither video nor audio are linked");
}
beach:
@@ -3132,6 +3109,10 @@ gst_flv_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
+ /* Try to push upstream first */
+ ret = gst_pad_push_event (demux->sinkpad, event);
+ if (ret)
+ break;
if (demux->random_access) {
ret = gst_flv_demux_handle_seek_pull (demux, event, TRUE);
} else {
@@ -3159,6 +3140,11 @@ gst_flv_demux_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstFormat format;
+ /* Try to push upstream first */
+ res = gst_pad_peer_query (demux->sinkpad, query);
+ if (res)
+ goto beach;
+
gst_query_parse_duration (query, &format, NULL);
/* duration is time only */
@@ -3382,6 +3368,11 @@ gst_flv_demux_dispose (GObject * object)
demux->taglist = NULL;
}
+ if (demux->flowcombiner) {
+ gst_flow_combiner_free (demux->flowcombiner);
+ demux->flowcombiner = NULL;
+ }
+
if (demux->new_seg_event) {
gst_event_unref (demux->new_seg_event);
demux->new_seg_event = NULL;
@@ -3472,6 +3463,7 @@ gst_flv_demux_init (GstFlvDemux * demux)
demux->adapter = gst_adapter_new ();
demux->taglist = gst_tag_list_new_empty ();
+ demux->flowcombiner = gst_flow_combiner_new ();
gst_segment_init (&demux->segment, GST_FORMAT_TIME);
demux->own_index = FALSE;
diff --git a/gst/flv/gstflvdemux.h b/gst/flv/gstflvdemux.h
index 79a8902e..611482c3 100644
--- a/gst/flv/gstflvdemux.h
+++ b/gst/flv/gstflvdemux.h
@@ -22,6 +22,7 @@
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
#include "gstindex.h"
G_BEGIN_DECLS
@@ -74,6 +75,8 @@ struct _GstFlvDemux
GstAdapter *adapter;
+ GstFlowCombiner *flowcombiner;
+
GstSegment segment;
GstEvent *new_seg_event;
diff --git a/gst/isomp4/fourcc.h b/gst/isomp4/fourcc.h
index 64322a7a..4edf900b 100644
--- a/gst/isomp4/fourcc.h
+++ b/gst/isomp4/fourcc.h
@@ -304,6 +304,11 @@ G_BEGIN_DECLS
/* ilst metatags */
#define FOURCC__cmt GST_MAKE_FOURCC(0xa9, 'c','m','t')
+/* apple tags */
+#define FOURCC__mak GST_MAKE_FOURCC(0xa9, 'm','a','k')
+#define FOURCC__mod GST_MAKE_FOURCC(0xa9, 'm','o','d')
+#define FOURCC__swr GST_MAKE_FOURCC(0xa9, 's','w','r')
+
/* Chapters reference */
#define FOURCC_chap GST_MAKE_FOURCC('c','h','a','p')
diff --git a/gst/isomp4/qtdemux.c b/gst/isomp4/qtdemux.c
index 53847c00..7df62597 100644
--- a/gst/isomp4/qtdemux.c
+++ b/gst/isomp4/qtdemux.c
@@ -294,9 +294,6 @@ struct _QtDemuxStream
GstSegment segment;
guint32 segment_seqnum; /* segment event seqnum obtained from seek */
- /* last GstFlowReturn */
- GstFlowReturn last_ret;
-
/* quicktime segments */
guint32 n_segments;
QtDemuxSegment *segments;
@@ -467,7 +464,8 @@ static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
QtDemuxStream * stream);
-static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
+static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
+ QtDemuxStream * stream);
static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
static void qtdemux_do_allocation (GstQTDemux * qtdemux,
@@ -546,6 +544,7 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
qtdemux->have_group_id = FALSE;
qtdemux->group_id = G_MAXUINT;
gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
+ qtdemux->flowcombiner = gst_flow_combiner_new ();
GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
}
@@ -559,6 +558,7 @@ gst_qtdemux_dispose (GObject * object)
g_object_unref (G_OBJECT (qtdemux->adapter));
qtdemux->adapter = NULL;
}
+ gst_flow_combiner_free (qtdemux->flowcombiner);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -1397,7 +1397,6 @@ gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
stream->sample_index = -1;
stream->offset_in_sample = 0;
stream->segment_index = -1;
- stream->last_ret = GST_FLOW_OK;
stream->sent_eos = FALSE;
stream->segment_seqnum = seqnum;
@@ -1427,7 +1426,6 @@ gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
gboolean flush;
gboolean update;
GstSegment seeksegment;
- int i;
guint32 seqnum = 0;
GstEvent *flush_event;
@@ -1504,10 +1502,6 @@ gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
}
- /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
- for (i = 0; i < qtdemux->n_streams; i++)
- qtdemux->streams[i]->last_ret = GST_FLOW_OK;
-
gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
qtdemux->sinkpad, NULL);
@@ -1562,10 +1556,10 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
GstClockTime ts = gst_util_get_timestamp ();
#endif
- if (qtdemux->upstream_newsegment || qtdemux->fragmented) {
+ if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
/* seek should be handled by upstream, we might need to re-download fragments */
GST_DEBUG_OBJECT (qtdemux,
- "leting upstream handle seek for smoothstreaming");
+ "let upstream handle seek for fragmented playback");
goto upstream;
}
@@ -1715,7 +1709,6 @@ _create_stream (void)
stream->time_position = 0;
stream->sample_index = -1;
stream->offset_in_sample = 0;
- stream->last_ret = GST_FLOW_OK;
stream->new_stream = TRUE;
return stream;
}
@@ -1879,10 +1872,9 @@ gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
qtdemux->got_moov = FALSE;
} else if (qtdemux->mss_mode) {
for (n = 0; n < qtdemux->n_streams; n++)
- gst_qtdemux_stream_clear (qtdemux->streams[n]);
+ gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
} else {
for (n = 0; n < qtdemux->n_streams; n++) {
- qtdemux->streams[n]->last_ret = GST_FLOW_OK;
qtdemux->streams[n]->sent_eos = FALSE;
qtdemux->streams[n]->segment_seqnum = 0;
qtdemux->streams[n]->time_position = 0;
@@ -2130,7 +2122,7 @@ gst_qtdemux_stbl_free (QtDemuxStream * stream)
}
static void
-gst_qtdemux_stream_clear (QtDemuxStream * stream)
+gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
{
if (stream->allocator)
gst_object_unref (stream->allocator);
@@ -2154,7 +2146,6 @@ gst_qtdemux_stream_clear (QtDemuxStream * stream)
/* free stbl sub-atoms */
gst_qtdemux_stbl_free (stream);
- stream->last_ret = GST_FLOW_OK;
stream->sent_eos = FALSE;
stream->segment_index = -1;
stream->time_position = 0;
@@ -2167,12 +2158,14 @@ gst_qtdemux_stream_clear (QtDemuxStream * stream)
static void
gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
{
- gst_qtdemux_stream_clear (stream);
+ gst_qtdemux_stream_clear (qtdemux, stream);
if (stream->caps)
gst_caps_unref (stream->caps);
stream->caps = NULL;
- if (stream->pad)
+ if (stream->pad) {
gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
+ gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
+ }
g_free (stream);
}
@@ -3511,8 +3504,6 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
stream->segment_seqnum = 0;
}
gst_pad_push_event (stream->pad, event);
- /* assume we can send more data now */
- stream->last_ret = GST_FLOW_OK;
/* clear to send tags on this pad now */
gst_qtdemux_push_tags (qtdemux, stream);
}
@@ -3817,42 +3808,12 @@ gst_qtdemux_sync_streams (GstQTDemux * demux)
* GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
*/
static GstFlowReturn
-gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
- GstFlowReturn ret)
+gst_qtdemux_combine_flows (GstQTDemux * demux, GstFlowReturn ret)
{
- gint i;
- gboolean unexpected = FALSE, not_linked = TRUE;
-
GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
- /* store the value */
- stream->last_ret = ret;
-
- /* any other error that is not-linked or eos can be returned right away */
- if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
- goto done;
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
- /* only return NOT_LINKED if all other pads returned NOT_LINKED */
- for (i = 0; i < demux->n_streams; i++) {
- QtDemuxStream *ostream = demux->streams[i];
-
- ret = ostream->last_ret;
-
- /* no unexpected or unlinked, return */
- if (G_LIKELY (ret != GST_FLOW_EOS && ret != GST_FLOW_NOT_LINKED))
- goto done;
-
- /* we check to see if we have at least 1 unexpected or all unlinked */
- unexpected |= (ret == GST_FLOW_EOS);
- not_linked &= (ret == GST_FLOW_NOT_LINKED);
- }
-
- /* when we get here, we all have unlinked or unexpected */
- if (not_linked)
- ret = GST_FLOW_NOT_LINKED;
- else if (unexpected)
- ret = GST_FLOW_EOS;
-done:
GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
return ret;
}
@@ -4287,7 +4248,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
goto next;
/* last pushed sample was out of boundary, goto next sample */
- if (G_UNLIKELY (stream->last_ret == GST_FLOW_EOS))
+ if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
goto next;
if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
@@ -4346,7 +4307,7 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
}
/* combine flows */
- ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
+ ret = gst_qtdemux_combine_flows (qtdemux, ret);
/* ignore unlinked, we will not push on the pad anymore and we will EOS when
* we have no more data for the pad to push */
if (ret == GST_FLOW_EOS)
@@ -5121,7 +5082,7 @@ gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
}
/* combine flows */
- ret = gst_qtdemux_combine_flows (demux, stream, ret);
+ ret = gst_qtdemux_combine_flows (demux, ret);
} else {
/* skip this data, stream is EOS */
gst_adapter_flush (demux->adapter, demux->neededbytes);
@@ -6020,6 +5981,7 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux,
GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
+ gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
if (stream->pending_tags)
gst_tag_list_unref (stream->pending_tags);
@@ -6952,6 +6914,12 @@ qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
fourcc = QT_FOURCC (stsd_data + 4);
data = stsd_data + 8;
+ if (size == 0) {
+ GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
+ "svq3 atom parsing");
+ goto end;
+ }
+
switch (fourcc) {
case FOURCC_gama:{
if (size == 12) {
@@ -7170,6 +7138,93 @@ bad_data:
return 0;
}
+static gboolean
+qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
+ GstByteReader * reader, guint32 * matrix, const gchar * atom)
+{
+ /*
+ * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
+ * [0 1 2]
+ * [3 4 5]
+ * [6 7 8]
+ */
+
+ if (gst_byte_reader_get_remaining (reader) < 36)
+ return FALSE;
+
+ matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
+ matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
+
+ GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
+ GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
+ matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
+ matrix[2] & 0xFF);
+ GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
+ matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
+ matrix[5] & 0xFF);
+ GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
+ matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
+ matrix[8] & 0xFF);
+
+ return TRUE;
+}
+
+static void
+qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
+ QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
+{
+
+/* [a b c]
+ * [d e f]
+ * [g h i]
+ *
+ * This macro will only compare value abdegh, it expects cfi to have already
+ * been checked
+ */
+#define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
+ (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
+ (m)[6] == (g << 16) && (m)[7] == (h << 16))
+
+ /* only handle the cases where the last column has standard values */
+ if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
+ const gchar *rotation_tag = NULL;
+
+ /* no rotation needed */
+ if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
+ /* NOP */
+ } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
+ stream->display_height, 0)) {
+ rotation_tag = "rotate-90";
+ } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
+ stream->display_width, stream->display_height)) {
+ rotation_tag = "rotate-180";
+ } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
+ stream->display_width)) {
+ rotation_tag = "rotate-270";
+ } else {
+ GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
+ }
+
+ GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
+ rotation_tag);
+ if (rotation_tag != NULL) {
+ if (*taglist == NULL)
+ *taglist = gst_tag_list_new_empty ();
+ gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
+ GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
+ }
+ } else {
+ GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
+ }
+}
+
/* parse the traks.
* With each track we associate a new QtDemuxStream that contains all the info
* about the trak.
@@ -7380,19 +7435,27 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
guint32 w = 0, h = 0;
gboolean gray;
gint depth, palette_size, palette_count;
+ guint32 matrix[9];
guint32 *palette_data = NULL;
stream->sampled = TRUE;
/* version 1 uses some 64-bit ints */
- if (!gst_byte_reader_skip (&tkhd, 56 + value_size)
- || !gst_byte_reader_get_uint32_be (&tkhd, &w)
+ if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
+ goto corrupt_file;
+
+ if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
+ goto corrupt_file;
+
+ if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
|| !gst_byte_reader_get_uint32_be (&tkhd, &h))
goto corrupt_file;
stream->display_width = w >> 16;
stream->display_height = h >> 16;
+ qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, &list);
+
offset = 16;
if (len < 86)
goto corrupt_file;
@@ -7496,7 +7559,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
}
if (codec) {
- list = gst_tag_list_new_empty ();
+ if (list == NULL)
+ list = gst_tag_list_new_empty ();
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
GST_TAG_VIDEO_CODEC, codec, NULL);
g_free (codec);
@@ -8276,7 +8340,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
GstStructure *s;
gint bitrate = 0;
- list = gst_tag_list_new_empty ();
+ if (list == NULL)
+ list = gst_tag_list_new_empty ();
gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
GST_TAG_AUDIO_CODEC, codec, NULL);
g_free (codec);
@@ -8886,6 +8951,7 @@ qtdemux_expose_streams (GstQTDemux * qtdemux)
gst_pad_push_event (oldpad, gst_event_new_eos ());
gst_pad_set_active (oldpad, FALSE);
gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
+ gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
gst_object_unref (oldpad);
}
@@ -9728,6 +9794,9 @@ static const struct
FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
qtdemux_tag_add_classification}, {
+ FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
+ FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
+ FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
/* This is a special case, some tags are stored in this
* 'reverse dns naming', according to:
diff --git a/gst/isomp4/qtdemux.h b/gst/isomp4/qtdemux.h
index 3fe01954..47c82029 100644
--- a/gst/isomp4/qtdemux.h
+++ b/gst/isomp4/qtdemux.h
@@ -23,6 +23,7 @@
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
+#include <gst/base/gstflowcombiner.h>
G_BEGIN_DECLS
@@ -64,6 +65,8 @@ struct _GstQTDemux {
gint n_audio_streams;
gint n_sub_streams;
+ GstFlowCombiner *flowcombiner;
+
gboolean have_group_id;
guint group_id;
diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c
index 7fa71590..63ecfe1b 100644
--- a/gst/matroska/matroska-demux.c
+++ b/gst/matroska/matroska-demux.c
@@ -190,6 +190,7 @@ gst_matroska_demux_finalize (GObject * object)
GstMatroskaDemux *demux = GST_MATROSKA_DEMUX (object);
gst_matroska_read_common_finalize (&demux->common);
+ gst_flow_combiner_free (demux->flowcombiner);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@@ -266,44 +267,7 @@ gst_matroska_demux_init (GstMatroskaDemux * demux)
/* finish off */
gst_matroska_demux_reset (GST_ELEMENT (demux));
-}
-
-/*
- * Returns the aggregated GstFlowReturn.
- */
-static GstFlowReturn
-gst_matroska_demux_combine_flows (GstMatroskaDemux * demux,
- GstMatroskaTrackContext * track, GstFlowReturn ret)
-{
- guint i;
-
- /* store the value */
- track->last_flow = ret;
-
- /* any other error that is not-linked can be returned right away */
- if (ret != GST_FLOW_NOT_LINKED)
- goto done;
-
- /* only return NOT_LINKED if all other pads returned NOT_LINKED */
- g_assert (demux->common.src->len == demux->common.num_streams);
- for (i = 0; i < demux->common.src->len; i++) {
- GstMatroskaTrackContext *ostream = g_ptr_array_index (demux->common.src,
- i);
-
- if (ostream == NULL)
- continue;
-
- ret = ostream->last_flow;
- /* some other return value (must be SUCCESS but we can return
- * other values as well) */
- if (ret != GST_FLOW_NOT_LINKED)
- goto done;
- }
- /* if we get here, all other pads were unlinked and we return
- * NOT_LINKED then */
-done:
- GST_LOG_OBJECT (demux, "combined return %s", gst_flow_get_name (ret));
- return ret;
+ demux->flowcombiner = gst_flow_combiner_new ();
}
static void
@@ -459,7 +423,6 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
context->flags =
GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
GST_MATROSKA_TRACK_LACING;
- context->last_flow = GST_FLOW_OK;
context->from_time = GST_CLOCK_TIME_NONE;
context->from_offset = -1;
context->to_offset = G_MAXINT64;
@@ -1271,6 +1234,7 @@ gst_matroska_demux_add_stream (GstMatroskaDemux * demux, GstEbmlRead * ebml)
gst_pad_set_caps (context->pad, context->caps);
gst_element_add_pad (GST_ELEMENT (demux), context->pad);
+ gst_flow_combiner_add_pad (demux->flowcombiner, context->pad);
g_free (padname);
@@ -2555,7 +2519,7 @@ gst_matroska_demux_push_stream_headers (GstMatroskaDemux * demux,
stream->stream_headers = NULL;
/* combine flows */
- ret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
return ret;
}
@@ -3657,7 +3621,7 @@ gst_matroska_demux_parse_blockgroup_or_simpleblock (GstMatroskaDemux * demux,
}
}
/* combine flows */
- ret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
next_lace:
size -= lace_size[n];
@@ -3683,7 +3647,7 @@ eos:
stream->eos = TRUE;
ret = GST_FLOW_OK;
/* combine flows */
- ret = gst_matroska_demux_combine_flows (demux, stream, ret);
+ ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
goto done;
}
invalid_lacing:
diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h
index 4453fe8f..36a686da 100644
--- a/gst/matroska/matroska-demux.h
+++ b/gst/matroska/matroska-demux.h
@@ -24,6 +24,7 @@
#define __GST_MATROSKA_DEMUX_H__
#include <gst/gst.h>
+#include <gst/base/gstflowcombiner.h>
#include "ebml-read.h"
#include "matroska-ids.h"
@@ -58,6 +59,8 @@ typedef struct _GstMatroskaDemux {
guint group_id;
gboolean have_group_id;
+ GstFlowCombiner *flowcombiner;
+
/* state */
gboolean streaming;
guint level_up;
diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h
index f7eea2b5..68a68d40 100644
--- a/gst/matroska/matroska-ids.h
+++ b/gst/matroska/matroska-ids.h
@@ -497,7 +497,6 @@ struct _GstMatroskaTrackContext {
GstPad *pad;
GstCaps *caps;
guint index;
- GstFlowReturn last_flow;
/* reverse playback */
GstClockTime from_time;
gint64 from_offset;
diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c
index c53bcf3f..4d3cb421 100644
--- a/gst/matroska/matroska-parse.c
+++ b/gst/matroska/matroska-parse.c
@@ -299,7 +299,6 @@ gst_matroska_parse_add_stream (GstMatroskaParse * parse, GstEbmlRead * ebml)
context->flags =
GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT |
GST_MATROSKA_TRACK_LACING;
- context->last_flow = GST_FLOW_OK;
context->to_offset = G_MAXINT64;
context->alignment = 1;
parse->common.num_streams++;
diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c
index ae5ea463..73381baf 100644
--- a/gst/matroska/matroska-read-common.c
+++ b/gst/matroska/matroska-read-common.c
@@ -1213,7 +1213,7 @@ gst_matroska_read_common_parse_header (GstMatroskaReadCommon * common,
if (num != GST_EBML_VERSION) {
GST_ERROR_OBJECT (ebml, "Unsupported EBML version %" G_GUINT64_FORMAT,
num);
- return GST_FLOW_ERROR;
+ goto exit_error;
}
GST_DEBUG_OBJECT (ebml, "EbmlReadVersion: %" G_GUINT64_FORMAT, num);
@@ -2959,8 +2959,6 @@ gst_matroska_read_common_reset_streams (GstMatroskaReadCommon * common,
context->set_discont = TRUE;
context->eos = FALSE;
context->from_time = GST_CLOCK_TIME_NONE;
- if (full)
- context->last_flow = GST_FLOW_OK;
if (context->type == GST_MATROSKA_TRACK_TYPE_VIDEO) {
GstMatroskaTrackVideoContext *videocontext =
(GstMatroskaTrackVideoContext *) context;
diff --git a/gst/multipart/multipartdemux.c b/gst/multipart/multipartdemux.c
index 7ba880c6..a62c2a06 100644
--- a/gst/multipart/multipartdemux.c
+++ b/gst/multipart/multipartdemux.c
@@ -188,6 +188,8 @@ gst_multipart_demux_init (GstMultipartDemux * multipart)
multipart->header_completed = FALSE;
multipart->scanpos = 0;
multipart->singleStream = DEFAULT_SINGLE_STREAM;
+ multipart->have_group_id = FALSE;
+ multipart->group_id = G_MAXUINT;
}
static void
@@ -296,6 +298,8 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime,
gchar *name;
const gchar *capsname;
GstCaps *caps;
+ gchar *stream_id;
+ GstEvent *event;
mppad = g_new0 (GstMultipartPad, 1);
@@ -316,17 +320,42 @@ gst_multipart_find_pad_by_mime (GstMultipartDemux * demux, gchar * mime,
demux->srcpads = g_slist_prepend (demux->srcpads, mppad);
demux->numpads++;
+ gst_pad_use_fixed_caps (pad);
+ gst_pad_set_active (pad, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (demux), pad);
+
+ /* prepare and send stream-start */
+ if (!demux->have_group_id) {
+ event = gst_pad_get_sticky_event (demux->sinkpad,
+ GST_EVENT_STREAM_START, 0);
+
+ if (event) {
+ demux->have_group_id =
+ gst_event_parse_group_id (event, &demux->group_id);
+ gst_event_unref (event);
+ } else if (!demux->have_group_id) {
+ demux->have_group_id = TRUE;
+ demux->group_id = gst_util_group_id_next ();
+ }
+ }
+
+ stream_id = gst_pad_create_stream_id (pad,
+ GST_ELEMENT_CAST (demux), demux->mime_type);
+
+ event = gst_event_new_stream_start (stream_id);
+ if (demux->have_group_id)
+ gst_event_set_group_id (event, demux->group_id);
+
+ gst_pad_push_event (pad, event);
+ g_free (stream_id);
+
/* take the mime type, convert it to the caps name */
capsname = gst_multipart_demux_get_gstname (demux, mime);
caps = gst_caps_from_string (capsname);
GST_DEBUG_OBJECT (demux, "caps for pad: %s", capsname);
- gst_pad_use_fixed_caps (pad);
- gst_pad_set_active (pad, TRUE);
gst_pad_set_caps (pad, caps);
gst_caps_unref (caps);
- gst_element_add_pad (GST_ELEMENT_CAST (demux), pad);
-
if (created) {
*created = TRUE;
}
@@ -592,6 +621,9 @@ gst_multipart_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
if (G_UNLIKELY (datalen <= 0)) {
GST_DEBUG_OBJECT (multipart, "skipping empty content.");
gst_adapter_flush (adapter, size - datalen);
+ } else if (G_UNLIKELY (!multipart->mime_type)) {
+ GST_DEBUG_OBJECT (multipart, "content has no MIME type.");
+ gst_adapter_flush (adapter, size - datalen);
} else {
GstClockTime ts;
@@ -677,6 +709,8 @@ gst_multipart_demux_change_state (GstElement * element,
multipart->content_length = -1;
multipart->scanpos = 0;
gst_multipart_demux_remove_src_pads (multipart);
+ multipart->have_group_id = FALSE;
+ multipart->group_id = G_MAXUINT;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
diff --git a/gst/multipart/multipartdemux.h b/gst/multipart/multipartdemux.h
index 4db33c26..cb81a83d 100644
--- a/gst/multipart/multipartdemux.h
+++ b/gst/multipart/multipartdemux.h
@@ -87,6 +87,10 @@ struct _GstMultipartDemux
gint scanpos;
gboolean singleStream;
+
+ /* to handle stream-start */
+ gboolean have_group_id;
+ guint group_id;
};
struct _GstMultipartDemuxClass
diff --git a/gst/rtp/gstrtpdvpay.c b/gst/rtp/gstrtpdvpay.c
index d779f123..db75cf65 100644
--- a/gst/rtp/gstrtpdvpay.c
+++ b/gst/rtp/gstrtpdvpay.c
@@ -300,7 +300,12 @@ gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
max_payload_size = ((GST_RTP_BASE_PAYLOAD_MTU (rtpdvpay) - hdrlen) / 80) * 80;
/* The length of the buffer to transmit. */
- gst_buffer_map (buffer, &map, GST_MAP_READ);
+ if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
+ GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+ (NULL), ("Failed to map buffer"));
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
data = map.data;
size = map.size;
@@ -327,7 +332,13 @@ gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
outbuf = gst_rtp_buffer_new_allocate (max_payload_size, 0, 0);
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer);
- gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
+ if (!gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp)) {
+ gst_buffer_unref (outbuf);
+ GST_ELEMENT_ERROR (rtpdvpay, CORE, FAILED,
+ (NULL), ("Failed to map RTP buffer"));
+ ret = GST_FLOW_ERROR;
+ goto beach;
+ }
dest = gst_rtp_buffer_get_payload (&rtp);
filled = 0;
}
@@ -368,6 +379,8 @@ gst_rtp_dv_pay_handle_buffer (GstRTPBasePayload * basepayload,
outbuf = NULL;
}
}
+
+beach:
gst_buffer_unmap (buffer, &map);
gst_buffer_unref (buffer);
diff --git a/gst/rtp/gstrtpg729pay.c b/gst/rtp/gstrtpg729pay.c
index 898bcd12..306e1757 100644
--- a/gst/rtp/gstrtpg729pay.c
+++ b/gst/rtp/gstrtpg729pay.c
@@ -204,6 +204,17 @@ gst_rtp_g729_pay_push (GstRTPG729Pay * rtpg729pay,
return ret;
}
+static GstFlowReturn
+gst_rtp_g729_pay_push_and_free (GstRTPG729Pay * rtpg729pay,
+ guint8 * data, guint payload_len)
+{
+ GstFlowReturn ret;
+
+ ret = gst_rtp_g729_pay_push (rtpg729pay, data, payload_len);
+ g_free (data);
+ return ret;
+}
+
static void
gst_rtp_g729_pay_recalc_rtp_time (GstRTPG729Pay * rtpg729pay, GstClockTime time)
{
@@ -309,7 +320,7 @@ gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
if (GST_BUFFER_IS_DISCONT (buf)) {
/* flush remainder */
if (available > 0) {
- gst_rtp_g729_pay_push (rtpg729pay,
+ gst_rtp_g729_pay_push_and_free (rtpg729pay,
gst_adapter_take (adapter, available), available);
available = 0;
}
@@ -354,7 +365,7 @@ gst_rtp_g729_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buf)
(available / G729_FRAME_SIZE) * G729_FRAME_SIZE);
}
- ret = gst_rtp_g729_pay_push (rtpg729pay,
+ ret = gst_rtp_g729_pay_push_and_free (rtpg729pay,
gst_adapter_take (adapter, payload_len), payload_len);
available -= payload_len;
}
diff --git a/gst/rtp/gstrtpgstpay.c b/gst/rtp/gstrtpgstpay.c
index 016cefe9..c0a9d94d 100644
--- a/gst/rtp/gstrtpgstpay.c
+++ b/gst/rtp/gstrtpgstpay.c
@@ -257,12 +257,13 @@ gst_rtp_gst_pay_change_state (GstElement * element, GstStateChange transition)
return ret;
}
+#define RTP_HEADER_LEN 12
static gboolean
gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
GstClockTime timestamp)
{
- guint avail;
+ guint avail, mtu;
guint frag_offset;
GstBufferList *list;
@@ -270,7 +271,9 @@ gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
if (avail == 0)
return FALSE;
- list = gst_buffer_list_new ();
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay);
+
+ list = gst_buffer_list_new_sized ((avail / (mtu - (RTP_HEADER_LEN + 8))) + 1);
frag_offset = 0;
while (avail) {
@@ -287,7 +290,7 @@ gst_rtp_gst_pay_create_from_adapter (GstRtpGSTPay * rtpgstpay,
packet_len = gst_rtp_buffer_calc_packet_len (8 + avail, 0, 0);
/* fill one MTU or all available bytes */
- towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpgstpay));
+ towrite = MIN (packet_len, mtu);
/* this is the payload length */
payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
diff --git a/gst/rtp/gstrtph263pay.c b/gst/rtp/gstrtph263pay.c
index a9672ec1..4de0fabd 100644
--- a/gst/rtp/gstrtph263pay.c
+++ b/gst/rtp/gstrtph263pay.c
@@ -958,7 +958,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
GST_DEBUG ("MCBPC index: %d", mb_type_index);
if (mb_type_index == -1) {
GST_ERROR ("MB index shouldn't be -1 in window: %08x", context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
@@ -977,7 +977,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
GST_DEBUG ("CBPY index: %d", cbpy_type_index);
if (cbpy_type_index == -1) {
GST_ERROR ("CBPY index shouldn't be -1 in window: %08x", context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
@@ -1018,7 +1018,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
if (tcoef_type_index == -1) {
GST_ERROR ("TCOEF index shouldn't be -1 in window: %08x",
context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
gst_rtp_h263_pay_move_window_right (context,
@@ -1069,7 +1069,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
GST_DEBUG ("MCBPC index: %d", mb_type_index);
if (mb_type_index == -1) {
GST_ERROR ("MB index shouldn't be -1 in window: %08x", context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
gst_rtp_h263_pay_move_window_right (context, mcbpc_P[mb_type_index][2],
@@ -1087,7 +1087,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
GST_DEBUG ("CBPY index: %d", cbpy_type_index);
if (cbpy_type_index == -1) {
GST_ERROR ("CBPY index shouldn't be -1 in window: %08x", context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
gst_rtp_h263_pay_move_window_right (context, cbpy_P[cbpy_type_index][2],
@@ -1121,7 +1121,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
if (mvd_type == -1) {
GST_ERROR ("MVD1-4 index shouldn't be -1 in window: %08x",
context->window);
- return NULL;
+ goto beach;
}
//set the MB mvd values
mac->mvd[j] = mvd[mvd_type][3];
@@ -1166,7 +1166,7 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
if (tcoef_type_index == -1) {
GST_ERROR ("TCOEF index shouldn't be -1 in window: %08x",
context->window);
- return NULL;
+ goto beach;
}
mac->ebit =
@@ -1193,6 +1193,10 @@ gst_rtp_h263_pay_B_mbfinder (GstRtpH263PayContext * context,
mac->length = mac->end - mac->start + 1;
return mac;
+
+beach:
+ gst_rtp_h263_pay_mb_destroy (mac);
+ return NULL;
}
static GstRtpH263PayMB *
@@ -1709,7 +1713,8 @@ gst_rtp_h263_pay_flush (GstRtpH263Pay * rtph263pay)
if (!gst_rtp_h263_pay_mode_B_fragment (rtph263pay, context,
context->gobs[i])) {
GST_ERROR ("There was an error fragmenting in mode B");
- return GST_FLOW_ERROR;
+ ret = GST_FLOW_ERROR;
+ goto end;
}
} else {
//IMPLEMENT C mode
diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c
index a7b52bda..586cf734 100644
--- a/gst/rtp/gstrtph264depay.c
+++ b/gst/rtp/gstrtph264depay.c
@@ -944,7 +944,11 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
memcpy (map.data + sizeof (sync_bytes), payload, nalu_size);
gst_buffer_unmap (outbuf, &map);
- gst_adapter_push (rtph264depay->adapter, outbuf);
+ outbuf =
+ gst_rtp_h264_depay_handle_nal (rtph264depay, outbuf, timestamp,
+ marker);
+ if (outbuf)
+ gst_adapter_push (rtph264depay->adapter, outbuf);
payload += nalu_size;
payload_len -= nalu_size;
diff --git a/gst/rtp/gstrtph264pay.c b/gst/rtp/gstrtph264pay.c
index 5fb15ceb..3d835aeb 100644
--- a/gst/rtp/gstrtph264pay.c
+++ b/gst/rtp/gstrtph264pay.c
@@ -166,6 +166,8 @@ gst_rtp_h264_pay_init (GstRtpH264Pay * rtph264pay)
(GDestroyNotify) gst_buffer_unref);
rtph264pay->last_spspps = -1;
rtph264pay->spspps_interval = DEFAULT_CONFIG_INTERVAL;
+ rtph264pay->delta_unit = FALSE;
+ rtph264pay->discont = FALSE;
rtph264pay->adapter = gst_adapter_new ();
}
@@ -704,7 +706,8 @@ gst_rtp_h264_pay_decode_nal (GstRtpH264Pay * payloader,
static GstFlowReturn
gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
- GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au);
+ GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+ gboolean delta_unit, gboolean discont);
static GstFlowReturn
gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
@@ -721,7 +724,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
GST_DEBUG_OBJECT (rtph264pay, "inserting SPS in the stream");
/* resend SPS */
ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (sps_buf),
- dts, pts, FALSE);
+ dts, pts, FALSE, FALSE, FALSE);
/* Not critical here; but throw a warning */
if (ret != GST_FLOW_OK) {
sent_all_sps_pps = FALSE;
@@ -735,7 +738,7 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
GST_DEBUG_OBJECT (rtph264pay, "inserting PPS in the stream");
/* resend PPS */
ret = gst_rtp_h264_pay_payload_nal (basepayload, gst_buffer_ref (pps_buf),
- dts, pts, FALSE);
+ dts, pts, FALSE, FALSE, FALSE);
/* Not critical here; but throw a warning */
if (ret != GST_FLOW_OK) {
sent_all_sps_pps = FALSE;
@@ -749,9 +752,15 @@ gst_rtp_h264_pay_send_sps_pps (GstRTPBasePayload * basepayload,
return ret;
}
+/* @delta_unit: if %FALSE the first packet sent won't have the
+ * GST_BUFFER_FLAG_DELTA_UNIT flag.
+ * @discont: if %TRUE the first packet sent will have the
+ * GST_BUFFER_FLAG_DISCONT flag.
+ */
static GstFlowReturn
gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
- GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au)
+ GstBuffer * paybuf, GstClockTime dts, GstClockTime pts, gboolean end_of_au,
+ gboolean delta_unit, gboolean discont)
{
GstRtpH264Pay *rtph264pay;
GstFlowReturn ret;
@@ -824,12 +833,11 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
packet_len = gst_rtp_buffer_calc_packet_len (size, 0, 0);
if (packet_len < mtu) {
+ /* will fit in one packet */
GST_DEBUG_OBJECT (basepayload,
"NAL Unit fit in one packet datasize=%d mtu=%d", size, mtu);
- /* will fit in one packet */
- /* use buffer lists
- * create buffer without payload containing only the RTP header
+ /* create buffer without payload containing only the RTP header
* (memory block at index 0) */
outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
@@ -844,18 +852,25 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
GST_BUFFER_PTS (outbuf) = pts;
GST_BUFFER_DTS (outbuf) = dts;
- /* insert payload memory block */
- outbuf = gst_buffer_append (outbuf, paybuf);
-
- list = gst_buffer_list_new ();
+ if (!delta_unit)
+ /* Only the first packet sent should not have the flag */
+ delta_unit = TRUE;
+ else
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
- /* add the buffer to the buffer list */
- gst_buffer_list_add (list, outbuf);
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first packet sent should have the flag */
+ discont = FALSE;
+ }
gst_rtp_buffer_unmap (&rtp);
- /* push the list to the next element in the pipe */
- ret = gst_rtp_base_payload_push_list (basepayload, list);
+ /* insert payload memory block */
+ outbuf = gst_buffer_append (outbuf, paybuf);
+
+ /* push the buffer to the next element */
+ ret = gst_rtp_base_payload_push (basepayload, outbuf);
} else {
/* fragmentation Units FU-A */
guint limitedSize;
@@ -875,7 +890,7 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
/* We keep 2 bytes for FU indicator and FU Header */
payload_len = gst_rtp_buffer_calc_payload_len (mtu - 2, 0, 0);
- list = gst_buffer_list_new ();
+ list = gst_buffer_list_new_sized ((size / payload_len) + 1);
while (end == 0) {
limitedSize = size < payload_len ? size : payload_len;
@@ -915,6 +930,18 @@ gst_rtp_h264_pay_payload_nal (GstRTPBasePayload * basepayload,
gst_buffer_copy_region (paybuf, GST_BUFFER_COPY_MEMORY, pos,
limitedSize));
+ if (!delta_unit)
+ /* Only the first packet sent should not have the flag */
+ delta_unit = TRUE;
+ else
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
+
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first packet sent should have the flag */
+ discont = FALSE;
+ }
+
/* add the buffer to the buffer list */
gst_buffer_list_add (list, outbuf);
@@ -946,6 +973,8 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
gboolean avc;
GstBuffer *paybuf = NULL;
gsize skip;
+ gboolean delayed_not_delta_unit = FALSE;
+ gboolean delayed_discont = FALSE;
rtph264pay = GST_RTP_H264_PAY (basepayload);
@@ -962,11 +991,34 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
size = map.size;
pts = GST_BUFFER_PTS (buffer);
dts = GST_BUFFER_DTS (buffer);
+ rtph264pay->delta_unit = GST_BUFFER_FLAG_IS_SET (buffer,
+ GST_BUFFER_FLAG_DELTA_UNIT);
+ rtph264pay->discont = GST_BUFFER_IS_DISCONT (buffer);
GST_DEBUG_OBJECT (basepayload, "got %" G_GSIZE_FORMAT " bytes", size);
} else {
dts = gst_adapter_prev_dts (rtph264pay->adapter, NULL);
pts = gst_adapter_prev_pts (rtph264pay->adapter, NULL);
if (buffer) {
+ if (!GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) {
+ if (gst_adapter_available (rtph264pay->adapter) == 0)
+ rtph264pay->delta_unit = FALSE;
+ else
+ /* This buffer contains a key frame but the adapter isn't empty. So
+ * we'll purge it first by sending a first packet and then the second
+ * one won't have the DELTA_UNIT flag. */
+ delayed_not_delta_unit = TRUE;
+ }
+
+ if (GST_BUFFER_IS_DISCONT (buffer)) {
+ if (gst_adapter_available (rtph264pay->adapter) == 0)
+ rtph264pay->discont = TRUE;
+ else
+ /* This buffer has the DISCONT flag but the adapter isn't empty. So
+ * we'll purge it first by sending a first packet and then the second
+ * one will have the DISCONT flag set. */
+ delayed_discont = TRUE;
+ }
+
if (!GST_CLOCK_TIME_IS_VALID (dts))
dts = GST_BUFFER_DTS (buffer);
if (!GST_CLOCK_TIME_IS_VALID (pts))
@@ -1030,7 +1082,16 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
nal_len);
ret =
gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
- end_of_au);
+ end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+ if (!rtph264pay->delta_unit)
+ /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+ rtph264pay->delta_unit = TRUE;
+
+ if (rtph264pay->discont)
+ /* Only the first outgoing packet have the DISCONT flag */
+ rtph264pay->discont = FALSE;
+
if (ret != GST_FLOW_OK)
break;
@@ -1161,7 +1222,24 @@ gst_rtp_h264_pay_handle_buffer (GstRTPBasePayload * basepayload,
/* put the data in one or more RTP packets */
ret =
gst_rtp_h264_pay_payload_nal (basepayload, paybuf, dts, pts,
- end_of_au);
+ end_of_au, rtph264pay->delta_unit, rtph264pay->discont);
+
+ if (delayed_not_delta_unit) {
+ rtph264pay->delta_unit = FALSE;
+ delayed_not_delta_unit = FALSE;
+ } else {
+ /* Only the first outgoing packet doesn't have the DELTA_UNIT flag */
+ rtph264pay->delta_unit = TRUE;
+ }
+
+ if (delayed_discont) {
+ rtph264pay->discont = TRUE;
+ delayed_discont = FALSE;
+ } else {
+ /* Only the first outgoing packet have the DISCONT flag */
+ rtph264pay->discont = FALSE;
+ }
+
if (ret != GST_FLOW_OK) {
break;
}
diff --git a/gst/rtp/gstrtph264pay.h b/gst/rtp/gstrtph264pay.h
index e1f6c7f1..44f7af44 100644
--- a/gst/rtp/gstrtph264pay.h
+++ b/gst/rtp/gstrtph264pay.h
@@ -74,6 +74,11 @@ struct _GstRtpH264Pay
guint spspps_interval;
gboolean send_spspps;
GstClockTime last_spspps;
+
+ /* TRUE if the next NALU processed should have the DELTA_UNIT flag */
+ gboolean delta_unit;
+ /* TRUE if the next NALU processed should have the DISCONT flag */
+ gboolean discont;
};
struct _GstRtpH264PayClass
diff --git a/gst/rtp/gstrtpj2kpay.c b/gst/rtp/gstrtpj2kpay.c
index 6cefc314..98880b29 100644
--- a/gst/rtp/gstrtpj2kpay.c
+++ b/gst/rtp/gstrtpj2kpay.c
@@ -353,11 +353,11 @@ gst_rtp_j2k_pay_handle_buffer (GstRTPBasePayload * basepayload,
state.next_sot = 0;
state.force_packet = FALSE;
- list = gst_buffer_list_new ();
-
/* get max packet length */
max_size = gst_rtp_buffer_calc_payload_len (mtu - HEADER_SIZE, 0, 0);
+ list = gst_buffer_list_new_sized ((mtu / max_size) + 1);
+
do {
GstBuffer *outbuf;
guint8 *header;
diff --git a/gst/rtp/gstrtpjpegpay.c b/gst/rtp/gstrtpjpegpay.c
index 227d8ddb..3e820a08 100644
--- a/gst/rtp/gstrtpjpegpay.c
+++ b/gst/rtp/gstrtpjpegpay.c
@@ -662,6 +662,8 @@ gst_rtp_jpeg_pay_scan_marker (const guint8 * data, guint size, guint * offset)
}
}
+#define RTP_HEADER_LEN 12
+
static GstFlowReturn
gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
GstBuffer * buffer)
@@ -678,7 +680,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
GstMapInfo map;
guint8 *data;
gsize size;
- guint mtu;
+ guint mtu, max_payload_size;
guint bytes_left;
guint jpeg_header_size = 0;
guint offset;
@@ -686,6 +688,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
gboolean sos_found, sof_found, dqt_found, dri_found;
gint i;
GstBufferList *list = NULL;
+ gboolean discont;
pay = GST_RTP_JPEG_PAY (basepayload);
mtu = GST_RTP_BASE_PAYLOAD_MTU (pay);
@@ -695,6 +698,7 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
size = map.size;
timestamp = GST_BUFFER_TIMESTAMP (buffer);
offset = 0;
+ discont = GST_BUFFER_IS_DISCONT (buffer);
GST_LOG_OBJECT (pay, "got buffer size %" G_GSIZE_FORMAT
" , timestamp %" GST_TIME_FORMAT, size, GST_TIME_ARGS (timestamp));
@@ -802,13 +806,14 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
GST_LOG_OBJECT (pay, "quant_data size %u", quant_data_size);
- list = gst_buffer_list_new ();
-
bytes_left = sizeof (jpeg_header) + quant_data_size + size;
if (dri_found)
bytes_left += sizeof (restart_marker_header);
+ max_payload_size = mtu - (RTP_HEADER_LEN + sizeof (jpeg_header));
+ list = gst_buffer_list_new_sized ((bytes_left / max_payload_size) + 1);
+
frame_done = FALSE;
do {
GstBuffer *outbuf;
@@ -892,6 +897,12 @@ gst_rtp_jpeg_pay_handle_buffer (GstRTPBasePayload * basepayload,
GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
+ if (discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first outputted buffer has the DISCONT flag */
+ discont = FALSE;
+ }
+
/* and add to list */
gst_buffer_list_insert (list, -1, outbuf);
diff --git a/gst/rtp/gstrtpmp4gpay.c b/gst/rtp/gstrtpmp4gpay.c
index 7913d9ab..e374e5cd 100644
--- a/gst/rtp/gstrtpmp4gpay.c
+++ b/gst/rtp/gstrtpmp4gpay.c
@@ -543,6 +543,12 @@ gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
rtpmp4gpay->offset += rtpmp4gpay->frame_len;
}
+ if (rtpmp4gpay->discont) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
+ /* Only the first outputted buffer has the DISCONT flag */
+ rtpmp4gpay->discont = FALSE;
+ }
+
ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpmp4gpay), outbuf);
avail -= payload_len;
@@ -563,6 +569,7 @@ gst_rtp_mp4g_pay_handle_buffer (GstRTPBasePayload * basepayload,
rtpmp4gpay->first_timestamp = GST_BUFFER_TIMESTAMP (buffer);
rtpmp4gpay->first_duration = GST_BUFFER_DURATION (buffer);
+ rtpmp4gpay->discont = GST_BUFFER_IS_DISCONT (buffer);
/* we always encode and flush a full AU */
gst_adapter_push (rtpmp4gpay->adapter, buffer);
diff --git a/gst/rtp/gstrtpmp4gpay.h b/gst/rtp/gstrtpmp4gpay.h
index fed9c930..7506fad9 100644
--- a/gst/rtp/gstrtpmp4gpay.h
+++ b/gst/rtp/gstrtpmp4gpay.h
@@ -47,6 +47,7 @@ struct _GstRtpMP4GPay
GstAdapter *adapter;
GstClockTime first_timestamp;
GstClockTime first_duration;
+ gboolean discont;
GstClockTime duration;
guint64 offset;
diff --git a/gst/rtp/gstrtpmp4vpay.c b/gst/rtp/gstrtpmp4vpay.c
index 8ac6d061..56cf9f73 100644
--- a/gst/rtp/gstrtpmp4vpay.c
+++ b/gst/rtp/gstrtpmp4vpay.c
@@ -223,10 +223,12 @@ gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
gst_adapter_clear (rtpmp4vpay->adapter);
}
+#define RTP_HEADER_LEN 12
+
static GstFlowReturn
gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
{
- guint avail;
+ guint avail, mtu;
GstBuffer *outbuf;
GstBuffer *outbuf_data = NULL;
GstFlowReturn ret;
@@ -248,12 +250,12 @@ gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
if (!avail)
return GST_FLOW_OK;
- ret = GST_FLOW_OK;
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (rtpmp4vpay);
/* Use buffer lists. Each frame will be put into a list
* of buffers and the whole list will be pushed downstream
* at once */
- list = gst_buffer_list_new ();
+ list = gst_buffer_list_new_sized ((avail / (mtu - RTP_HEADER_LEN)) + 1);
while (avail > 0) {
guint towrite;
@@ -265,7 +267,7 @@ gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
/* fill one MTU or all available bytes */
- towrite = MIN (packet_len, GST_RTP_BASE_PAYLOAD_MTU (rtpmp4vpay));
+ towrite = MIN (packet_len, mtu);
/* this is the payload length */
payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
diff --git a/gst/rtp/gstrtptheoradepay.c b/gst/rtp/gstrtptheoradepay.c
index 39c8d2ac..ccfe12db 100644
--- a/gst/rtp/gstrtptheoradepay.c
+++ b/gst/rtp/gstrtptheoradepay.c
@@ -570,19 +570,16 @@ gst_rtp_theora_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
break;
}
- g_free (to_free);
-
if (rtptheoradepay->needs_keyframe)
goto request_keyframe;
+out:
+no_output:
+
gst_rtp_buffer_unmap (&rtp);
+ g_free (to_free);
return NULL;
-no_output:
- {
- gst_rtp_buffer_unmap (&rtp);
- return NULL;
- }
/* ERORRS */
switch_failed:
{
@@ -599,8 +596,7 @@ packet_short:
ignore_reserved:
{
GST_WARNING_OBJECT (rtptheoradepay, "reserved TDT ignored");
- gst_rtp_buffer_unmap (&rtp);
- return NULL;
+ goto out;
}
length_short:
{
@@ -621,8 +617,7 @@ request_config:
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
gst_structure_new ("GstForceKeyUnit",
"all-headers", G_TYPE_BOOLEAN, TRUE, NULL)));
- gst_rtp_buffer_unmap (&rtp);
- return NULL;
+ goto out;
}
request_keyframe:
{
@@ -630,8 +625,7 @@ request_keyframe:
gst_pad_push_event (GST_RTP_BASE_DEPAYLOAD_SINKPAD (depayload),
gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM,
gst_structure_new_empty ("GstForceKeyUnit")));
- gst_rtp_buffer_unmap (&rtp);
- return NULL;
+ goto out;
}
}
diff --git a/gst/rtp/gstrtpvp8depay.c b/gst/rtp/gstrtpvp8depay.c
index 7cc4504a..40f3375e 100644
--- a/gst/rtp/gstrtpvp8depay.c
+++ b/gst/rtp/gstrtpvp8depay.c
@@ -106,7 +106,7 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf)
GstRtpVP8Depay *self = GST_RTP_VP8_DEPAY (depay);
GstBuffer *payload;
guint8 *data;
- guint offset;
+ guint hdrsize;
guint size;
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
@@ -134,31 +134,32 @@ gst_rtp_vp8_depay_process (GstRTPBaseDepayload * depay, GstBuffer * buf)
self->started = TRUE;
}
- offset = 1;
+ hdrsize = 1;
/* Check X optional header */
if ((data[0] & 0x80) != 0) {
- offset++;
+ hdrsize++;
/* Check I optional header */
if ((data[1] & 0x80) != 0) {
- offset++;
- if (G_UNLIKELY (offset + 2 >= size))
+ if (G_UNLIKELY (size < 3))
goto too_small;
+ hdrsize++;
/* Check for 16 bits PictureID */
if ((data[2] & 0x80) != 0)
- offset++;
+ hdrsize++;
}
/* Check L optional header */
if ((data[1] & 0x40) != 0)
- offset++;
+ hdrsize++;
/* Check T or K optional headers */
if ((data[1] & 0x20) != 0 || (data[1] & 0x10) != 0)
- offset++;
+ hdrsize++;
}
+ GST_DEBUG_OBJECT (depay, "hdrsize %u, size %u", hdrsize, size);
- if (G_UNLIKELY (offset >= size))
+ if (G_UNLIKELY (hdrsize >= size))
goto too_small;
- payload = gst_rtp_buffer_get_payload_subbuffer (&rtpbuffer, offset, -1);
+ payload = gst_rtp_buffer_get_payload_subbuffer (&rtpbuffer, hdrsize, -1);
gst_adapter_push (self->adapter, payload);
/* Marker indicates that it was the last rtp packet for this frame */
diff --git a/gst/rtp/gstrtpvp8pay.c b/gst/rtp/gstrtpvp8pay.c
index 47837819..f3ad8455 100644
--- a/gst/rtp/gstrtpvp8pay.c
+++ b/gst/rtp/gstrtpvp8pay.c
@@ -171,12 +171,13 @@ gst_rtp_vp8_pay_get_property (GObject * object,
}
static gboolean
-gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
+gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer,
+ gsize buffer_size)
{
- GstBitReader *reader = NULL;
+ GstMapInfo map = GST_MAP_INFO_INIT;
+ GstBitReader reader;
guint8 *data;
gsize size;
- GstMapInfo map;
int i;
gboolean keyframe;
guint32 partition0_size;
@@ -187,7 +188,7 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
BOOL_DECODER bc;
guint8 *pdata;
- if (G_UNLIKELY (gst_buffer_get_size (buffer) < 3))
+ if (G_UNLIKELY (buffer_size < 3))
goto error;
if (!gst_buffer_map (buffer, &map, GST_MAP_READ) || !map.data)
@@ -195,7 +196,8 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
data = map.data;
size = map.size;
- reader = gst_bit_reader_new (data, size);
+
+ gst_bit_reader_init (&reader, data, size);
self->is_keyframe = keyframe = ((data[0] & 0x1) == 0);
version = (data[0] >> 1) & 0x7;
@@ -212,22 +214,22 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
offset = keyframe ? 10 : 3;
partition0_size += offset;
- if (!gst_bit_reader_skip (reader, 24))
+ if (!gst_bit_reader_skip (&reader, 24))
goto error;
if (keyframe) {
/* check start tag: 0x9d 0x01 0x2a */
- if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x9d)
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x9d)
goto error;
- if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x01)
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x01)
goto error;
- if (!gst_bit_reader_get_bits_uint8 (reader, &tmp8, 8) || tmp8 != 0x2a)
+ if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp8, 8) || tmp8 != 0x2a)
goto error;
/* Skip horizontal size code (16 bits) vertical size code (16 bits) */
- if (!gst_bit_reader_skip (reader, 32))
+ if (!gst_bit_reader_skip (&reader, 32))
goto error;
}
@@ -332,14 +334,12 @@ gst_rtp_vp8_pay_parse_frame (GstRtpVP8Pay * self, GstBuffer * buffer)
self->partition_offset[i + 1] = size;
- gst_bit_reader_free (reader);
gst_buffer_unmap (buffer, &map);
return TRUE;
error:
GST_DEBUG ("Failed to parse frame");
- if (reader) {
- gst_bit_reader_free (reader);
+ if (map.memory != NULL) {
gst_buffer_unmap (buffer, &map);
}
return FALSE;
@@ -373,16 +373,7 @@ gst_rtp_vp8_calc_header_len (GstRtpVP8Pay * self)
}
}
-static gsize
-gst_rtp_vp8_calc_payload_len (GstRtpVP8Pay * self)
-{
- GstRTPBasePayload *payload = GST_RTP_BASE_PAYLOAD (self);
-
- return gst_rtp_buffer_calc_payload_len (GST_RTP_BASE_PAYLOAD_MTU (payload) -
- gst_rtp_vp8_calc_header_len (self), 0, 0);
-}
-
-/* When growing the vp8 header keep gst_rtp_vp8_calc_payload_len in sync */
+/* When growing the vp8 header keep max payload len calculation in sync */
static GstBuffer *
gst_rtp_vp8_create_header_buffer (GstRtpVP8Pay * self, guint8 partid,
gboolean start, gboolean mark, GstBuffer * in)
@@ -423,8 +414,8 @@ gst_rtp_vp8_create_header_buffer (GstRtpVP8Pay * self, guint8 partid,
static guint
-gst_rtp_vp8_payload_next (GstRtpVP8Pay * self,
- GstBufferList * list, guint offset, GstBuffer * buffer)
+gst_rtp_vp8_payload_next (GstRtpVP8Pay * self, GstBufferList * list,
+ guint offset, GstBuffer * buffer, gsize buffer_size, gsize max_payload_len)
{
guint partition;
GstBuffer *header;
@@ -434,8 +425,8 @@ gst_rtp_vp8_payload_next (GstRtpVP8Pay * self,
gsize remaining;
gsize available;
- remaining = gst_buffer_get_size (buffer) - offset;
- available = gst_rtp_vp8_calc_payload_len (self);
+ remaining = buffer_size - offset;
+ available = max_payload_len;
if (available > remaining)
available = remaining;
@@ -462,17 +453,28 @@ gst_rtp_vp8_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
GstRtpVP8Pay *self = GST_RTP_VP8_PAY (payload);
GstFlowReturn ret;
GstBufferList *list;
- guint offset;
+ gsize size, max_paylen;
+ guint offset, mtu, vp8_hdr_len;
+
+ size = gst_buffer_get_size (buffer);
- if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer))) {
- g_message ("Failed to parse frame");
+ if (G_UNLIKELY (!gst_rtp_vp8_pay_parse_frame (self, buffer, size))) {
+ GST_ELEMENT_ERROR (self, STREAM, ENCODE, (NULL),
+ ("Failed to parse VP8 frame"));
return GST_FLOW_ERROR;
}
- list = gst_buffer_list_new ();
+ mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
+ vp8_hdr_len = gst_rtp_vp8_calc_header_len (self);
+ max_paylen = gst_rtp_buffer_calc_payload_len (mtu - vp8_hdr_len, 0, 0);
- for (offset = 0; offset < gst_buffer_get_size (buffer);)
- offset += gst_rtp_vp8_payload_next (self, list, offset, buffer);
+ list = gst_buffer_list_new_sized ((size / max_paylen) + 1);
+
+ offset = 0;
+ while (offset < size) {
+ offset +=
+ gst_rtp_vp8_payload_next (self, list, offset, buffer, size, max_paylen);
+ }
ret = gst_rtp_base_payload_push_list (payload, list);
diff --git a/gst/rtp/gstrtpvrawpay.c b/gst/rtp/gstrtpvrawpay.c
index cade1786..c03c8d2f 100644
--- a/gst/rtp/gstrtpvrawpay.c
+++ b/gst/rtp/gstrtpvrawpay.c
@@ -27,6 +27,13 @@
#include "gstrtpvrawpay.h"
+enum
+{
+ PROP_CHUNKS_PER_FRAME = 1
+};
+
+#define DEFAULT_CHUNKS_PER_FRAME 10
+
GST_DEBUG_CATEGORY_STATIC (rtpvrawpay_debug);
#define GST_CAT_DEFAULT (rtpvrawpay_debug)
@@ -70,6 +77,10 @@ static gboolean gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload,
GstCaps * caps);
static GstFlowReturn gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload *
payload, GstBuffer * buffer);
+static void gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
@@ -77,10 +88,23 @@ G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
{
GstRTPBasePayloadClass *gstrtpbasepayload_class;
GstElementClass *gstelement_class;
+ GObjectClass *gobject_class;
+ gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
+ gobject_class->set_property = gst_rtp_vraw_pay_set_property;
+ gobject_class->get_property = gst_rtp_vraw_pay_get_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_CHUNKS_PER_FRAME,
+ g_param_spec_int ("chunks-per-frame", "Chunks per Frame",
+ "Split and send out each frame in multiple chunks to reduce overhead",
+ 1, G_MAXINT, DEFAULT_CHUNKS_PER_FRAME,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+ );
+
gstrtpbasepayload_class->set_caps = gst_rtp_vraw_pay_setcaps;
gstrtpbasepayload_class->handle_buffer = gst_rtp_vraw_pay_handle_buffer;
@@ -101,6 +125,7 @@ G_DEFINE_TYPE (GstRtpVRawPay, gst_rtp_vraw_pay, GST_TYPE_RTP_BASE_PAYLOAD)
static void
gst_rtp_vraw_pay_init (GstRtpVRawPay * rtpvrawpay)
{
+ rtpvrawpay->chunks_per_frame = DEFAULT_CHUNKS_PER_FRAME;
}
static gboolean
@@ -111,7 +136,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
gint pgroup, xinc, yinc;
const gchar *depthstr, *samplingstr, *colorimetrystr;
gchar *wstr, *hstr;
- gint depth;
GstVideoInfo info;
rtpvrawpay = GST_RTP_VRAW_PAY (payload);
@@ -138,7 +162,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
/* these values are the only thing we can do */
depthstr = "8";
- depth = 8;
switch (GST_VIDEO_INFO_FORMAT (&info)) {
case GST_VIDEO_FORMAT_RGBA:
@@ -180,7 +203,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
samplingstr = "YCbCr-4:2:2";
pgroup = 5;
xinc = 2;
- depth = 10;
depthstr = "10";
break;
default:
@@ -195,7 +217,6 @@ gst_rtp_vraw_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
rtpvrawpay->pgroup = pgroup;
rtpvrawpay->xinc = xinc;
rtpvrawpay->yinc = yinc;
- rtpvrawpay->depth = depth;
GST_DEBUG_OBJECT (payload, "width %d, height %d, sampling %s",
GST_VIDEO_INFO_WIDTH (&info), GST_VIDEO_INFO_HEIGHT (&info), samplingstr);
@@ -239,15 +260,24 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
{
GstRtpVRawPay *rtpvrawpay;
GstFlowReturn ret = GST_FLOW_OK;
+ gfloat packets_per_packline;
+ guint pgroups_per_packet;
+ guint packlines_per_list, buffers_per_list;
+ guint lines_delay; /* after how many packed lines we push out a buffer list */
+ guint last_line; /* last pack line number we pushed out a buffer list */
guint line, offset;
guint8 *p0, *yp, *up, *vp;
guint ystride, uvstride;
+ guint xinc, yinc;
guint pgroup;
guint mtu;
guint width, height;
- gint field;
+ gint field, fields;
+ GstVideoFormat format;
GstVideoFrame frame;
gint interlaced;
+ gboolean use_buffer_lists;
+ GstBufferList *list = NULL;
GstRTPBuffer rtp = { NULL, };
rtpvrawpay = GST_RTP_VRAW_PAY (payload);
@@ -275,17 +305,40 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
interlaced = GST_VIDEO_INFO_IS_INTERLACED (&rtpvrawpay->vinfo);
+ format = GST_VIDEO_INFO_FORMAT (&rtpvrawpay->vinfo);
+
+ yinc = rtpvrawpay->yinc;
+ xinc = rtpvrawpay->xinc;
+
+ /* after how many packed lines we push out a buffer list */
+ lines_delay = GST_ROUND_UP_4 (height / rtpvrawpay->chunks_per_frame);
+
+ /* calculate how many buffers we expect to store in a single buffer list */
+ pgroups_per_packet = (mtu - (12 + 14)) / pgroup;
+ packets_per_packline = width / (xinc * pgroups_per_packet * 1.0);
+ packlines_per_list = height / (yinc * rtpvrawpay->chunks_per_frame);
+ buffers_per_list = packlines_per_list * packets_per_packline;
+ buffers_per_list = GST_ROUND_UP_8 (buffers_per_list);
+
+ use_buffer_lists = (rtpvrawpay->chunks_per_frame < (height / yinc));
+
+ fields = 1 + interlaced;
+
/* start with line 0, offset 0 */
- for (field = 0; field < 1 + interlaced; field++) {
+ for (field = 0; field < fields; field++) {
line = field;
offset = 0;
+ last_line = 0;
+
+ if (use_buffer_lists)
+ list = gst_buffer_list_new_sized (buffers_per_list);
/* write all lines */
while (line < height) {
- guint left;
+ guint left, pack_line;
GstBuffer *out;
guint8 *outdata, *headers;
- gboolean next_line;
+ gboolean next_line, complete = FALSE;
guint length, cont, pixels;
/* get the max allowed payload length size, we try to fill the complete MTU */
@@ -345,7 +398,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
/* get how may bytes we need for the remaining pixels */
pixels = width - offset;
- length = (pixels * pgroup) / rtpvrawpay->xinc;
+ length = (pixels * pgroup) / xinc;
if (left >= length) {
/* pixels and header fit completely, we will write them and skip to the
@@ -353,8 +406,8 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
next_line = TRUE;
} else {
/* line does not fit completely, see how many pixels fit */
- pixels = (left / pgroup) * rtpvrawpay->xinc;
- length = (pixels * pgroup) / rtpvrawpay->xinc;
+ pixels = (left / pgroup) * xinc;
+ length = (pixels * pgroup) / xinc;
next_line = FALSE;
}
GST_LOG_OBJECT (rtpvrawpay, "filling %u bytes in %u pixels", length,
@@ -371,7 +424,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
if (next_line) {
/* go to next line we do this here to make the check below easier */
- line += rtpvrawpay->yinc;
+ line += yinc;
}
/* calculate continuation marker */
@@ -412,14 +465,14 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
"writing length %u, line %u, offset %u, cont %d", length, lin, offs,
cont);
- switch (GST_VIDEO_INFO_FORMAT (&rtpvrawpay->vinfo)) {
+ switch (format) {
case GST_VIDEO_FORMAT_RGB:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_BGR:
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_UYVY:
case GST_VIDEO_FORMAT_UYVP:
- offs /= rtpvrawpay->xinc;
+ offs /= xinc;
memcpy (outdata, p0 + (lin * ystride) + (offs * pgroup), length);
outdata += length;
break;
@@ -446,8 +499,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
yd1p = yp + (lin * ystride) + (offs);
yd2p = yd1p + ystride;
- uvoff =
- (lin / rtpvrawpay->yinc * uvstride) + (offs / rtpvrawpay->xinc);
+ uvoff = (lin / yinc * uvstride) + (offs / xinc);
udp = up + uvoff;
vdp = vp + uvoff;
@@ -468,8 +520,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
guint8 *ydp, *udp, *vdp;
ydp = yp + (lin * ystride) + offs;
- uvoff =
- (lin / rtpvrawpay->yinc * uvstride) + (offs / rtpvrawpay->xinc);
+ uvoff = (lin / yinc * uvstride) + (offs / xinc);
udp = up + uvoff;
vdp = vp + uvoff;
@@ -496,6 +547,7 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
if (line >= height) {
GST_LOG_OBJECT (rtpvrawpay, "field/frame complete, set marker");
gst_rtp_buffer_set_marker (&rtp, TRUE);
+ complete = TRUE;
}
gst_rtp_buffer_unmap (&rtp);
if (left > 0) {
@@ -503,8 +555,26 @@ gst_rtp_vraw_pay_handle_buffer (GstRTPBasePayload * payload, GstBuffer * buffer)
gst_buffer_resize (out, 0, gst_buffer_get_size (out) - left);
}
- /* push buffer */
- ret = gst_rtp_base_payload_push (payload, out);
+ /* Now either push out the buffer directly */
+ if (!use_buffer_lists) {
+ ret = gst_rtp_base_payload_push (payload, out);
+ continue;
+ }
+
+ /* or add the buffer to buffer list ... */
+ gst_buffer_list_add (list, out);
+
+ /* .. and check if we need to push out the list */
+ pack_line = (line - field) / fields;
+ if (complete || (pack_line > last_line && pack_line % lines_delay == 0)) {
+ GST_LOG_OBJECT (rtpvrawpay, "pushing list of %u buffers up to pack "
+ "line %u", gst_buffer_list_length (list), pack_line);
+ ret = gst_rtp_base_payload_push_list (payload, list);
+ list = NULL;
+ if (!complete)
+ list = gst_buffer_list_new_sized (buffers_per_list);
+ last_line = pack_line;
+ }
}
}
@@ -533,6 +603,42 @@ too_small:
}
}
+static void
+gst_rtp_vraw_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpVRawPay *rtpvrawpay;
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CHUNKS_PER_FRAME:
+ rtpvrawpay->chunks_per_frame = g_value_get_int (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_vraw_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpVRawPay *rtpvrawpay;
+
+ rtpvrawpay = GST_RTP_VRAW_PAY (object);
+
+ switch (prop_id) {
+ case PROP_CHUNKS_PER_FRAME:
+ g_value_set_int (value, rtpvrawpay->chunks_per_frame);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
gboolean
gst_rtp_vraw_pay_plugin_init (GstPlugin * plugin)
{
diff --git a/gst/rtp/gstrtpvrawpay.h b/gst/rtp/gstrtpvrawpay.h
index 7cd86b8b..3fd2442d 100644
--- a/gst/rtp/gstrtpvrawpay.h
+++ b/gst/rtp/gstrtpvrawpay.h
@@ -48,11 +48,9 @@ struct _GstRtpVRawPay
gint pgroup;
gint xinc, yinc;
-// guint yp, up, vp;
-// gint ystride;
-// gint uvstride;
-// gboolean interlaced;
- gint depth;
+
+ /* properties */
+ guint chunks_per_frame;
};
struct _GstRtpVRawPayClass
diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c
index ffb0dee1..caeed748 100644
--- a/gst/rtsp/gstrtspsrc.c
+++ b/gst/rtsp/gstrtspsrc.c
@@ -123,6 +123,7 @@ enum
SIGNAL_ON_SDP,
SIGNAL_SELECT_STREAM,
SIGNAL_NEW_MANAGER,
+ SIGNAL_REQUEST_RTCP_KEY,
LAST_SIGNAL
};
@@ -163,6 +164,12 @@ gst_rtsp_src_buffer_mode_get_type (void)
return buffer_mode_type;
}
+#define AES_128_KEY_LEN 16
+#define AES_256_KEY_LEN 32
+
+#define HMAC_32_KEY_LEN 4
+#define HMAC_80_KEY_LEN 10
+
#define DEFAULT_LOCATION NULL
#define DEFAULT_PROTOCOLS GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP
#define DEFAULT_DEBUG FALSE
@@ -683,6 +690,21 @@ gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_CLEANUP, 0, NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
+ /**
+ * GstRTSPSrc::request-rtcp-key:
+ * @rtspsrc: a #GstRTSPSrc
+ * @num: the stream number
+ *
+ * Signal emited to get the crypto parameters relevant to the RTCP
+ * stream. User should provide the key and the RTCP encryption ciphers
+ * and authentication, and return them wrapped in a GstCaps.
+ *
+ * Since: 1.4
+ */
+ gst_rtspsrc_signals[SIGNAL_REQUEST_RTCP_KEY] =
+ g_signal_new ("request-rtcp-key", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_CAPS, 1, G_TYPE_UINT);
+
gstelement_class->send_event = gst_rtspsrc_send_event;
gstelement_class->provide_clock = gst_rtspsrc_provide_clock;
gstelement_class->change_state = gst_rtspsrc_change_state;
@@ -1537,8 +1559,8 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
gst_object_unref (stream->srtpenc);
if (stream->srtpdec)
gst_object_unref (stream->srtpdec);
- if (stream->key)
- gst_buffer_unref (stream->key);
+ if (stream->srtcpparams)
+ gst_caps_unref (stream->srtcpparams);
if (stream->rtcppad)
gst_object_unref (stream->rtcppad);
if (stream->session)
@@ -1738,6 +1760,18 @@ parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
break;
}
break;
+ case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
+ switch (param->val[0]) {
+ case AES_128_KEY_LEN:
+ srtp_cipher = "aes-128-icm";
+ break;
+ case AES_256_KEY_LEN:
+ srtp_cipher = "aes-256-icm";
+ break;
+ default:
+ break;
+ }
+ break;
case GST_MIKEY_SP_SRTP_AUTH_ALG:
switch (param->val[0]) {
case 0:
@@ -1751,6 +1785,18 @@ parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
break;
}
break;
+ case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
+ switch (param->val[0]) {
+ case HMAC_32_KEY_LEN:
+ srtp_auth = "hmac-sha1-32";
+ break;
+ case HMAC_80_KEY_LEN:
+ srtp_auth = "hmac-sha1-80";
+ break;
+ default:
+ break;
+ }
+ break;
case GST_MIKEY_SP_SRTP_SRTP_ENC:
break;
case GST_MIKEY_SP_SRTP_SRTCP_ENC:
@@ -3006,12 +3052,40 @@ request_rtcp_encoder (GstElement * rtpbin, guint session,
return NULL;
if (stream->srtpenc == NULL) {
+ GstStructure *s;
+
name = g_strdup_printf ("srtpenc_%u", session);
stream->srtpenc = gst_element_factory_make ("srtpenc", name);
g_free (name);
- /* key has been made before */
- g_object_set (stream->srtpenc, "key", stream->key, NULL);
+ /* get RTCP crypto parameters from caps */
+ s = gst_caps_get_structure (stream->srtcpparams, 0);
+ if (s) {
+ GstBuffer *buf;
+ const gchar *str;
+ GType ciphertype, authtype;
+ GValue rtcp_cipher = G_VALUE_INIT, rtcp_auth = G_VALUE_INIT;
+
+ ciphertype = g_type_from_name ("GstSrtpCipherType");
+ authtype = g_type_from_name ("GstSrtpAuthType");
+ g_value_init (&rtcp_cipher, ciphertype);
+ g_value_init (&rtcp_auth, authtype);
+
+ str = gst_structure_get_string (s, "srtcp-cipher");
+ gst_value_deserialize (&rtcp_cipher, str);
+ str = gst_structure_get_string (s, "srtcp-auth");
+ gst_value_deserialize (&rtcp_auth, str);
+ gst_structure_get (s, "srtp-key", GST_TYPE_BUFFER, &buf, NULL);
+
+ g_object_set_property (G_OBJECT (stream->srtpenc), "rtcp-cipher",
+ &rtcp_cipher);
+ g_object_set_property (G_OBJECT (stream->srtpenc), "rtcp-auth",
+ &rtcp_auth);
+ g_object_set (stream->srtpenc, "key", buf, NULL);
+
+ g_value_unset (&rtcp_cipher);
+ g_value_unset (&rtcp_auth);
+ }
}
name = g_strdup_printf ("rtcp_sink_%d", session);
pad = gst_element_get_request_pad (stream->srtpenc, name);
@@ -5812,27 +5886,102 @@ failed:
}
}
+static guint8
+enc_key_length_from_cipher_name (const gchar * cipher)
+{
+ if (g_strcmp0 (cipher, "aes-128-icm") == 0)
+ return AES_128_KEY_LEN;
+ else if (g_strcmp0 (cipher, "aes-256-icm") == 0)
+ return AES_256_KEY_LEN;
+ else {
+ GST_ERROR ("encryption algorithm '%s' not supported", cipher);
+ return 0;
+ }
+}
+
+static guint8
+auth_key_length_from_auth_name (const gchar * auth)
+{
+ if (g_strcmp0 (auth, "hmac-sha1-32") == 0)
+ return HMAC_32_KEY_LEN;
+ else if (g_strcmp0 (auth, "hmac-sha1-80") == 0)
+ return HMAC_80_KEY_LEN;
+ else {
+ GST_ERROR ("authentication algorithm '%s' not supported", auth);
+ return 0;
+ }
+}
+
+static GstCaps *
+signal_get_srtcp_params (GstRTSPSrc * src, GstRTSPStream * stream)
+{
+ GstCaps *caps = NULL;
+
+ g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_REQUEST_RTCP_KEY], 0,
+ stream->id, &caps);
+
+ if (caps != NULL)
+ GST_DEBUG_OBJECT (src, "SRTP parameters received");
+
+ return caps;
+}
+
+static GstCaps *
+default_srtcp_params (void)
+{
+ guint i;
+ GstCaps *caps;
+ GstBuffer *buf;
+ guint8 *key_data;
+#define KEY_SIZE 30
+
+ /* create a random key */
+ key_data = g_malloc (KEY_SIZE);
+ for (i = 0; i < KEY_SIZE; i += 4)
+ GST_WRITE_UINT32_BE (key_data + i, g_random_int ());
+
+ buf = gst_buffer_new_wrapped (key_data, KEY_SIZE);
+
+ caps = gst_caps_new_simple ("application/x-srtp",
+ "srtp-key", GST_TYPE_BUFFER, buf,
+ "srtcp-cipher", G_TYPE_STRING, "aes-128-icm",
+ "srtcp-auth", G_TYPE_STRING, "hmac-sha1-80", NULL);
+
+ return caps;
+}
+
static gchar *
gst_rtspsrc_stream_make_keymgmt (GstRTSPSrc * src, GstRTSPStream * stream)
{
GBytes *bytes;
gchar *result, *base64;
- guint8 *key_data;
const guint8 *data;
gsize size;
- guint i;
GstMIKEYMessage *msg;
GstMIKEYPayload *payload, *pkd;
guint8 byte;
-#define KEY_SIZE 30
+ GstStructure *s;
+ GstMapInfo info;
+ GstBuffer *srtpkey;
+ const GValue *val;
+ const gchar *srtcpcipher, *srtcpauth;
- key_data = g_malloc (KEY_SIZE);
- for (i = 0; i < KEY_SIZE; i += 4)
- GST_WRITE_UINT32_BE (key_data + i, g_random_int ());
+ stream->srtcpparams = signal_get_srtcp_params (src, stream);
+ if (stream->srtcpparams == NULL)
+ stream->srtcpparams = default_srtcp_params ();
+
+ s = gst_caps_get_structure (stream->srtcpparams, 0);
+
+ srtcpcipher = gst_structure_get_string (s, "srtcp-cipher");
+ srtcpauth = gst_structure_get_string (s, "srtcp-auth");
+ val = gst_structure_get_value (s, "srtp-key");
- if (stream->key)
- gst_buffer_unref (stream->key);
- stream->key = gst_buffer_new_wrapped (key_data, KEY_SIZE);
+ if (srtcpcipher == NULL || srtcpauth == NULL || val == NULL) {
+ GST_ERROR_OBJECT (src, "could not find the right SRTP parameters in caps");
+ return NULL;
+ }
+
+ srtpkey = gst_value_get_buffer (val);
msg = gst_mikey_message_new ();
/* unencrypted MIKEY message, we send this over TLS so this is allowed */
@@ -5852,9 +6001,17 @@ gst_rtspsrc_stream_make_keymgmt (GstRTSPSrc * src, GstRTSPStream * stream)
/* only AES-CM is supported */
byte = 1;
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_ALG, 1, &byte);
+ /* encryption key length */
+ byte = enc_key_length_from_cipher_name (srtcpcipher);
+ gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_ENC_KEY_LEN, 1,
+ &byte);
/* only HMAC-SHA1 */
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_ALG, 1,
&byte);
+ /* authentication key length */
+ byte = auth_key_length_from_auth_name (srtcpauth);
+ gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_AUTH_KEY_LEN, 1,
+ &byte);
/* we enable encryption on RTP and RTCP */
gst_mikey_payload_sp_add_param (payload, GST_MIKEY_SP_SRTP_SRTP_ENC, 1,
&byte);
@@ -5870,8 +6027,10 @@ gst_rtspsrc_stream_make_keymgmt (GstRTSPSrc * src, GstRTSPStream * stream)
gst_mikey_payload_kemac_set (payload, GST_MIKEY_ENC_NULL, GST_MIKEY_MAC_NULL);
/* add the key in KEMAC */
pkd = gst_mikey_payload_new (GST_MIKEY_PT_KEY_DATA);
- gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, KEY_SIZE,
- key_data);
+ gst_buffer_map (srtpkey, &info, GST_MAP_READ);
+ gst_mikey_payload_key_data_set_key (pkd, GST_MIKEY_KD_TEK, info.size,
+ info.data);
+ gst_buffer_unmap (srtpkey, &info);
gst_mikey_payload_kemac_add_sub (payload, pkd);
gst_mikey_message_add_payload (msg, payload);
diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h
index f38f6fce..e90d0599 100644
--- a/gst/rtsp/gstrtspsrc.h
+++ b/gst/rtsp/gstrtspsrc.h
@@ -137,7 +137,7 @@ struct _GstRTSPStream {
guint32 seqbase;
guint64 timebase;
GstElement *srtpdec;
- GstBuffer *key;
+ GstCaps *srtcpparams;
GstElement *srtpenc;
guint32 send_ssrc;
diff --git a/gst/udp/gstdynudpsink.c b/gst/udp/gstdynudpsink.c
index 328e9020..9c2b6bbd 100644
--- a/gst/udp/gstdynudpsink.c
+++ b/gst/udp/gstdynudpsink.c
@@ -21,10 +21,6 @@
* Boston, MA 02110-1301, USA.
*/
-/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -139,7 +135,8 @@ gst_dynudpsink_class_init (GstDynUDPSinkClass * klass)
gst_element_class_set_static_metadata (gstelement_class, "UDP packet sender",
"Sink/Network",
- "Send data over the network via UDP",
+ "Send data over the network via UDP with packet destinations picked up "
+ "dynamically from meta on the buffers passed",
"Philippe Khalaf <burger@speedy.org>");
gstbasesink_class->render = gst_dynudpsink_render;
@@ -267,9 +264,18 @@ gst_dynudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
send_error:
{
- GST_DEBUG ("got send error %s", err->message);
+ GstFlowReturn flow_ret;
+
+ if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ GST_DEBUG_OBJECT (sink, "send cancelled");
+ flow_ret = GST_FLOW_FLUSHING;
+ } else {
+ GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL),
+ ("send error: %s", err->message));
+ flow_ret = GST_FLOW_ERROR;
+ }
g_clear_error (&err);
- return GST_FLOW_ERROR;
+ return flow_ret;
}
invalid_family:
{
diff --git a/gst/udp/gstmultiudpsink.c b/gst/udp/gstmultiudpsink.c
index 988de2de..d3af62e7 100644
--- a/gst/udp/gstmultiudpsink.c
+++ b/gst/udp/gstmultiudpsink.c
@@ -29,10 +29,6 @@
* It can be combined with rtp payload encoders to implement RTP streaming.
*/
-/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -356,7 +352,8 @@ gst_multiudpsink_class_init (GstMultiUDPSinkClass * klass)
gst_element_class_set_static_metadata (gstelement_class, "UDP packet sender",
"Sink/Network",
- "Send data over the network via UDP",
+ "Send data over the network via UDP to one or multiple recipients "
+ "which can be added or removed at runtime using action signals",
"Wim Taymans <wim.taymans@gmail.com>");
gstbasesink_class->render = gst_multiudpsink_render;
@@ -529,7 +526,7 @@ gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
gint num, no_clients;
GError *err = NULL;
- sink = GST_MULTIUDPSINK (bsink);
+ sink = GST_MULTIUDPSINK_CAST (bsink);
n_mem = gst_buffer_n_memory (buffer);
if (n_mem == 0)
@@ -542,7 +539,7 @@ gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
size = 0;
for (i = 0; i < n_mem; i++) {
- mem = gst_buffer_get_memory (buffer, i);
+ mem = gst_buffer_peek_memory (buffer, i);
gst_memory_map (mem, &map[i], GST_MAP_READ);
vec[i].buffer = map[i].data;
@@ -616,10 +613,8 @@ gst_multiudpsink_render (GstBaseSink * bsink, GstBuffer * buffer)
g_mutex_unlock (&sink->client_lock);
/* unmap all memory again */
- for (i = 0; i < n_mem; i++) {
+ for (i = 0; i < n_mem; i++)
gst_memory_unmap (map[i].memory, &map[i]);
- gst_memory_unref (map[i].memory);
- }
GST_LOG_OBJECT (sink, "sent %" G_GSIZE_FORMAT " bytes to %d (of %d) clients",
size, num, no_clients);
@@ -637,10 +632,8 @@ flushing:
g_clear_error (&err);
/* unmap all memory */
- for (i = 0; i < n_mem; i++) {
+ for (i = 0; i < n_mem; i++)
gst_memory_unmap (map[i].memory, &map[i]);
- gst_memory_unref (map[i].memory);
- }
return GST_FLOW_FLUSHING;
}
@@ -1330,9 +1323,8 @@ gst_multiudpsink_remove (GstMultiUDPSink * sink, const gchar * host, gint port)
client->refcount--;
if (client->refcount == 0) {
GInetSocketAddress *saddr = G_INET_SOCKET_ADDRESS (client->addr);
+ GSocketFamily family = g_socket_address_get_family (client->addr);
GInetAddress *addr = g_inet_socket_address_get_address (saddr);
- GSocketFamily family =
- g_socket_address_get_family (G_SOCKET_ADDRESS (saddr));
GSocket *socket;
/* Select socket to send from for this address */
diff --git a/gst/udp/gstmultiudpsink.h b/gst/udp/gstmultiudpsink.h
index a1be566b..9b126bb6 100644
--- a/gst/udp/gstmultiudpsink.h
+++ b/gst/udp/gstmultiudpsink.h
@@ -33,6 +33,7 @@ G_BEGIN_DECLS
#define GST_MULTIUDPSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MULTIUDPSINK,GstMultiUDPSinkClass))
#define GST_IS_MULTIUDPSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULTIUDPSINK))
#define GST_IS_MULTIUDPSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULTIUDPSINK))
+#define GST_MULTIUDPSINK_CAST(obj) ((GstMultiUDPSink*)(obj))
typedef struct _GstMultiUDPSink GstMultiUDPSink;
typedef struct _GstMultiUDPSinkClass GstMultiUDPSinkClass;
diff --git a/gst/videobox/gstvideobox.c b/gst/videobox/gstvideobox.c
index 5df25883..861bcaea 100644
--- a/gst/videobox/gstvideobox.c
+++ b/gst/videobox/gstvideobox.c
@@ -2862,22 +2862,27 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
for (j = 0; j < gst_value_list_get_size (fval); j++) {
lval = gst_value_list_get_value (fval, j);
if ((str = g_value_get_string (lval))) {
- if (strstr (str, "RGB") || strstr (str, "BGR") ||
- strcmp (str, "AYUV") == 0)
+ if (strcmp (str, "AYUV") == 0) {
+ seen_yuv = TRUE;
+ seen_rgb = TRUE;
+ break;
+ } else if (strstr (str, "RGB") || strstr (str, "BGR")) {
seen_rgb = TRUE;
- else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0 ||
- strcmp (str, "AYUV") == 0)
+ } else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0) {
seen_yuv = TRUE;
+ }
}
}
} else if (fval && G_VALUE_HOLDS_STRING (fval)) {
if ((str = g_value_get_string (fval))) {
- if (strstr (str, "RGB") || strstr (str, "BGR") ||
- strcmp (str, "AYUV") == 0)
+ if (strcmp (str, "AYUV") == 0) {
+ seen_yuv = TRUE;
seen_rgb = TRUE;
- else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0 ||
- strcmp (str, "AYUV") == 0)
+ } else if (strstr (str, "RGB") || strstr (str, "BGR")) {
+ seen_rgb = TRUE;
+ } else if (strcmp (str, "I420") == 0 || strcmp (str, "YV12") == 0) {
seen_yuv = TRUE;
+ }
}
}
diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c
index e50a82d9..7e5f043b 100644
--- a/gst/wavparse/gstwavparse.c
+++ b/gst/wavparse/gstwavparse.c
@@ -1037,6 +1037,7 @@ gst_wavparse_stream_headers (GstWavParse * wav)
gchar *codec_name = NULL;
GstEvent **event_p;
gint64 upstream_size = 0;
+ GstStructure *s;
/* search for "_fmt" chunk, which should be first */
while (!wav->got_fmt) {
@@ -1107,6 +1108,15 @@ gst_wavparse_stream_headers (GstWavParse * wav)
if (!caps)
goto unknown_format;
+ /* If we got raw audio from upstream, we remove the codec_data field,
+ * which may have been added if the wav header included an extended
+ * chunk. We want to keep it for non raw audio.
+ */
+ s = gst_caps_get_structure (caps, 0);
+ if (s && gst_structure_has_name (s, "audio/x-raw")) {
+ gst_structure_remove_field (s, "codec_data");
+ }
+
/* do more sanity checks of header fields
* (these can be sanitized by gst_riff_create_audio_caps()
*/