<filename>gstreamer-plugins-base-&GST_API_VERSION;.pc</filename> and adding
<filename>-lgstrtp-&GST_API_VERSION;</filename> to the library flags.
</para>
+ <xi:include href="xml/gstrtpmeta.xml" />
<xi:include href="xml/gstrtpbaseaudiopayload.xml" />
<xi:include href="xml/gstrtpbasedepayload.xml" />
<xi:include href="xml/gstrtpbasepayload.xml" />
gst_rtp_base_depayload_push
gst_rtp_base_depayload_push_list
+gst_rtp_base_depayload_is_source_info_enabled
+gst_rtp_base_depayload_set_source_info_enabled
+
<SUBSECTION Standard>
GstRTPBaseDepayloadPrivate
GST_TYPE_RTP_BASE_DEPAYLOAD
gst_rtp_base_payload_push_list
gst_rtp_base_payload_set_options
gst_rtp_base_payload_set_outcaps
+
+gst_rtp_base_payload_allocate_output_buffer
+gst_rtp_base_payload_get_source_count
+gst_rtp_base_payload_is_source_info_enabled
+gst_rtp_base_payload_set_source_info_enabled
<SUBSECTION Standard>
GST_TYPE_RTP_BASE_PAYLOAD
GST_RTP_BASE_PAYLOAD
</SECTION>
<SECTION>
+<FILE>gstrtpmeta</FILE>
+<INCLUDE>gst/rtp/rtp.h</INCLUDE>
+GstRTPSourceMeta
+gst_buffer_add_rtp_source_meta
+gst_buffer_get_rtp_source_meta
+gst_rtp_source_meta_append_csrc
+gst_rtp_source_meta_get_info
+gst_rtp_source_meta_get_source_count
+gst_rtp_source_meta_set_ssrc
+GST_RTP_SOURCE_META_MAX_CSRC_COUNT
+<SUBSECTION Standard>
+gst_rtp_source_meta_api_get_type
+GST_RTP_SOURCE_META_API_TYPE
+GST_RTP_SOURCE_META_INFO
+</SECTION>
+
+<SECTION>
<FILE>gstrtcpbuffer</FILE>
<INCLUDE>gst/rtp/rtp.h</INCLUDE>
gstrtphdrext.h \
gstrtpbaseaudiopayload.h \
gstrtpbasepayload.h \
- gstrtpbasedepayload.h
+ gstrtpbasedepayload.h \
+ gstrtpmeta.h
lib_LTLIBRARIES = libgstrtp-@GST_API_VERSION@.la
gstrtphdrext.c \
gstrtpbaseaudiopayload.c \
gstrtpbasepayload.c \
- gstrtpbasedepayload.c
+ gstrtpbasedepayload.c \
+ gstrtpmeta.c
built_sources = gstrtp-enumtypes.c
built_headers = gstrtp-enumtypes.h
guint cached_max_length;
guint cached_ptime_multiple;
guint cached_align;
+ guint cached_csrc_count;
gboolean buffer_list;
};
payload_len, GST_TIME_ARGS (timestamp));
/* create buffer to hold the payload */
- outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
+ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload,
+ payload_len, 0, 0);
/* copy payload */
gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
payload_len, GST_TIME_ARGS (timestamp));
/* create just the RTP header buffer */
- outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
/* set metadata */
gst_rtp_base_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
/* create buffer to hold the payload */
- outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
+ outbuf = gst_rtp_base_payload_allocate_output_buffer (basepayload, 0, 0, 0);
paybuf = gst_adapter_take_buffer_fast (adapter, payload_len);
* mtu and min/max_ptime values. We cache those so that we don't have to redo
* all the calculations */
static gboolean
-gst_rtp_base_audio_payload_get_lengths (GstRTPBasePayload *
- basepayload, guint * min_payload_len, guint * max_payload_len,
+gst_rtp_base_audio_payload_get_lengths (GstRTPBasePayload * basepayload,
+ guint csrc_count, guint * min_payload_len, guint * max_payload_len,
guint * align)
{
GstRTPBaseAudioPayload *payload;
mtu = GST_RTP_BASE_PAYLOAD_MTU (payload);
- /* check cached values */
+ /* check cached values. Since csrc_count may vary for each packet, we only
+ * check whether the new value exceeds the cached value and thus result in
+ * smaller payload. */
if (G_LIKELY (priv->cached_mtu == mtu
&& priv->cached_ptime_multiple ==
basepayload->ptime_multiple
&& priv->cached_ptime == basepayload->ptime
&& priv->cached_max_ptime == basepayload->max_ptime
- && priv->cached_min_ptime == basepayload->min_ptime)) {
+ && priv->cached_min_ptime == basepayload->min_ptime
+ && priv->cached_csrc_count >= csrc_count)) {
/* if nothing changed, return cached values */
*min_payload_len = priv->cached_min_length;
*max_payload_len = priv->cached_max_length;
maxptime_octets = G_MAXUINT;
}
/* MTU max */
- max_mtu = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
+ max_mtu = gst_rtp_buffer_calc_payload_len (mtu, 0, csrc_count);
/* round down to alignment */
max_mtu = ALIGN_DOWN (max_mtu, *align);
priv->cached_min_length = *min_payload_len;
priv->cached_max_length = *max_payload_len;
priv->cached_align = *align;
+ priv->cached_csrc_count = csrc_count;
return TRUE;
}
}
}
- if (!gst_rtp_base_audio_payload_get_lengths (basepayload, &min_payload_len,
- &max_payload_len, &align))
+ if (!gst_rtp_base_audio_payload_get_lengths (basepayload,
+ gst_rtp_base_payload_get_source_count (basepayload, buffer),
+ &min_payload_len, &max_payload_len, &align))
goto config_error;
GST_DEBUG_OBJECT (payload,
#endif
#include "gstrtpbasedepayload.h"
+#include "gstrtpmeta.h"
GST_DEBUG_CATEGORY_STATIC (rtpbasedepayload_debug);
#define GST_CAT_DEFAULT (rtpbasedepayload_debug)
GstCaps *last_caps;
GstEvent *segment_event;
guint32 segment_seqnum; /* Note: this is a GstEvent seqnum */
+
+ gboolean source_info;
+ GstBuffer *input_buffer;
};
/* Filter signals and args */
LAST_SIGNAL
};
+#define DEFAULT_SOURCE_INFO FALSE
+
enum
{
PROP_0,
PROP_STATS,
+ PROP_SOURCE_INFO,
PROP_LAST
};
g_param_spec_boxed ("stats", "Statistics", "Various statistics",
GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRTPBaseDepayload:source-info:
+ *
+ * Add RTP source information found in RTP header as meta to output buffer.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property (gobject_class, PROP_SOURCE_INFO,
+ g_param_spec_boolean ("source-info", "RTP source information",
+ "Add RTP source information as buffer meta",
+ DEFAULT_SOURCE_INFO, G_PARAM_READWRITE));
+
gstelement_class->change_state = gst_rtp_base_depayload_change_state;
klass->packet_lost = gst_rtp_base_depayload_packet_lost;
priv->dts = -1;
priv->pts = -1;
priv->duration = -1;
+ priv->source_info = DEFAULT_SOURCE_INFO;
gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
}
filter->need_newsegment = FALSE;
}
+ priv->input_buffer = in;
+
if (process_rtp_packet_func != NULL) {
out_buf = process_rtp_packet_func (filter, &rtp);
gst_rtp_buffer_unmap (&rtp);
}
gst_buffer_unref (in);
+ priv->input_buffer = NULL;
return ret;
return event;
}
+static void
+add_rtp_source_meta (GstBuffer * outbuf, GstBuffer * rtpbuf)
+{
+ GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+ GstRTPSourceMeta *meta;
+ guint32 ssrc;
+
+ if (!gst_rtp_buffer_map (rtpbuf, GST_MAP_READ, &rtp))
+ return;
+
+ ssrc = gst_rtp_buffer_get_ssrc (&rtp);
+ meta = gst_buffer_add_rtp_source_meta (outbuf, &ssrc, NULL, 0);
+ if (meta != NULL) {
+ gint i;
+ gint csrc_count = gst_rtp_buffer_get_csrc_count (&rtp);
+ for (i = 0; i < csrc_count; i++) {
+ guint32 csrc = gst_rtp_buffer_get_csrc (&rtp, i);
+ gst_rtp_source_meta_append_csrc (meta, &csrc, 1);
+ }
+ }
+
+ gst_rtp_buffer_unmap (&rtp);
+}
+
static gboolean
set_headers (GstBuffer ** buffer, guint idx, GstRTPBaseDepayload * depayload)
{
priv->dts = GST_CLOCK_TIME_NONE;
priv->duration = GST_CLOCK_TIME_NONE;
+ if (priv->source_info && priv->input_buffer)
+ add_rtp_source_meta (*buffer, priv->input_buffer);
+
return TRUE;
}
gst_rtp_base_depayload_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
+ GstRTPBaseDepayload *depayload;
+
+ depayload = GST_RTP_BASE_DEPAYLOAD (object);
+
switch (prop_id) {
+ case PROP_SOURCE_INFO:
+ gst_rtp_base_depayload_set_source_info_enabled (depayload,
+ g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_take_boxed (value,
gst_rtp_base_depayload_create_stats (depayload));
break;
+ case PROP_SOURCE_INFO:
+ g_value_set_boolean (value,
+ gst_rtp_base_depayload_is_source_info_enabled (depayload));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+
+/**
+ * gst_rtp_base_depayload_set_source_info_enabled:
+ * @depayload: a #GstRTPBaseDepayload
+ * @enable: whether to add meta about RTP sources to buffer
+ *
+ * Enable or disable adding #GstRTPSourceMeta to depayloaded buffers.
+ *
+ * Since: 1.16
+ **/
+void
+gst_rtp_base_depayload_set_source_info_enabled (GstRTPBaseDepayload * depayload,
+ gboolean enable)
+{
+ depayload->priv->source_info = enable;
+}
+
+/**
+ * gst_rtp_base_depayload_is_source_info_enabled:
+ * @depayload: a #GstRTPBaseDepayload
+ *
+ * Queries whether #GstRTPSourceMeta will be added to depayloaded buffers.
+ *
+ * Returns: %TRUE if source-info is enabled.
+ *
+ * Since: 1.16
+ **/
+gboolean
+gst_rtp_base_depayload_is_source_info_enabled (GstRTPBaseDepayload * depayload)
+{
+ return depayload->priv->source_info;
+}
GST_RTP_API
GstFlowReturn gst_rtp_base_depayload_push_list (GstRTPBaseDepayload *filter, GstBufferList *out_list);
+GST_RTP_API
+gboolean gst_rtp_base_depayload_is_source_info_enabled (GstRTPBaseDepayload * depayload);
+
+GST_RTP_API
+void gst_rtp_base_depayload_set_source_info_enabled (GstRTPBaseDepayload * depayload,
+ gboolean enable);
+
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTPBaseDepayload, gst_object_unref)
#include <gst/rtp/gstrtpbuffer.h>
#include "gstrtpbasepayload.h"
+#include "gstrtpmeta.h"
GST_DEBUG_CATEGORY_STATIC (rtpbasepayload_debug);
#define GST_CAT_DEFAULT (rtpbasepayload_debug)
gboolean pt_set;
+ gboolean source_info;
+ GstBuffer *input_meta_buffer;
+
guint64 base_offset;
gint64 base_rtime;
guint64 base_rtime_hz;
#define DEFAULT_PERFECT_RTPTIME TRUE
#define DEFAULT_PTIME_MULTIPLE 0
#define DEFAULT_RUNNING_TIME GST_CLOCK_TIME_NONE
+#define DEFAULT_SOURCE_INFO FALSE
enum
{
PROP_PERFECT_RTPTIME,
PROP_PTIME_MULTIPLE,
PROP_STATS,
+ PROP_SOURCE_INFO,
PROP_LAST
};
g_param_spec_boxed ("stats", "Statistics", "Various statistics",
GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRTPBasePayload:source-info:
+ *
+ * Enable writing the CSRC field in allocated RTP header based on RTP source
+ * information found in the input buffer's #GstRTPSourceMeta.
+ *
+ * Since: 1.16
+ **/
+ g_object_class_install_property (gobject_class, PROP_SOURCE_INFO,
+ g_param_spec_boolean ("source-info", "RTP source information",
+ "Write CSRC based on buffer meta RTP source information",
+ DEFAULT_SOURCE_INFO, G_PARAM_READWRITE));
+
gstelement_class->change_state = gst_rtp_base_payload_change_state;
klass->get_caps = gst_rtp_base_payload_getcaps_default;
priv->ts_offset_random = (rtpbasepayload->ts_offset == -1);
priv->ssrc_random = (rtpbasepayload->ssrc == -1);
priv->pt_set = FALSE;
+ priv->source_info = DEFAULT_SOURCE_INFO;
rtpbasepayload->max_ptime = DEFAULT_MAX_PTIME;
rtpbasepayload->min_ptime = DEFAULT_MIN_PTIME;
if (!rtpbasepayload->priv->negotiated)
goto not_negotiated;
+ if (rtpbasepayload->priv->source_info) {
+ /* Save a copy of meta (instead of taking an extra reference before
+ * handle_buffer) to make the meta available when allocating a output
+ * buffer. */
+ rtpbasepayload->priv->input_meta_buffer = gst_buffer_new ();
+ gst_buffer_copy_into (rtpbasepayload->priv->input_meta_buffer, buffer,
+ GST_BUFFER_COPY_META, 0, -1);
+ }
+
if (gst_pad_check_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (rtpbasepayload))) {
if (!gst_rtp_base_payload_negotiate (rtpbasepayload)) {
gst_pad_mark_reconfigure (GST_RTP_BASE_PAYLOAD_SRCPAD (rtpbasepayload));
ret = rtpbasepayload_class->handle_buffer (rtpbasepayload, buffer);
+ gst_buffer_replace (&rtpbasepayload->priv->input_meta_buffer, NULL);
+
return ret;
/* ERRORS */
}
}
+static gboolean
+foreach_metadata_drop (GstBuffer * buffer, GstMeta ** meta, gpointer user_data)
+{
+ GType drop_api_type = (GType) GPOINTER_TO_INT (user_data);
+ const GstMetaInfo *info = (*meta)->info;
+
+ if (info->api == drop_api_type)
+ *meta = NULL;
+
+ return TRUE;
+}
+
+static gboolean
+filter_meta (GstBuffer ** buffer, guint idx, gpointer user_data)
+{
+ return gst_buffer_foreach_meta (*buffer, foreach_metadata_drop,
+ GINT_TO_POINTER (GST_RTP_SOURCE_META_API_TYPE));
+}
+
/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
* before the buffer is pushed. */
static GstFlowReturn
}
/* set ssrc, payload type, seq number, caps and rtptime */
+ /* remove unwanted meta */
if (is_list) {
gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), set_headers, &data);
+ gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj), filter_meta, NULL);
} else {
GstBuffer *buf = GST_BUFFER_CAST (obj);
set_headers (&buf, 0, &data);
+ filter_meta (&buf, 0, NULL);
}
priv->next_seqnum = data.seqnum;
(is_list) ? -1 : gst_buffer_get_size (GST_BUFFER (obj)),
payload->seqnum, data.rtptime, GST_TIME_ARGS (data.pts));
- if (g_atomic_int_compare_and_exchange (&payload->
- priv->notified_first_timestamp, 1, 0)) {
+ if (g_atomic_int_compare_and_exchange (&payload->priv->
+ notified_first_timestamp, 1, 0)) {
g_object_notify (G_OBJECT (payload), "timestamp");
g_object_notify (G_OBJECT (payload), "seqnum");
}
return res;
}
+/**
+ * gst_rtp_base_payload_allocate_output_buffer:
+ * @payload: a #GstRTPBasePayload
+ * @payload_len: the length of the payload
+ * @pad_len: the amount of padding
+ * @csrc_count: the minimum number of CSRC entries
+ *
+ * Allocate a new #GstBuffer with enough data to hold an RTP packet with
+ * minimum @csrc_count CSRCs, a payload length of @payload_len and padding of
+ * @pad_len. If @payload has #GstRTPBasePayload:source-info %TRUE additional
+ * CSRCs may be allocated and filled with RTP source information.
+ *
+ * Returns: A newly allocated buffer that can hold an RTP packet with given
+ * parameters.
+ *
+ * Since: 1.16
+ */
+GstBuffer *
+gst_rtp_base_payload_allocate_output_buffer (GstRTPBasePayload * payload,
+ guint payload_len, guint8 pad_len, guint8 csrc_count)
+{
+ GstBuffer *buffer = NULL;
+
+ if (payload->priv->input_meta_buffer != NULL) {
+ GstRTPSourceMeta *meta =
+ gst_buffer_get_rtp_source_meta (payload->priv->input_meta_buffer);
+ if (meta != NULL) {
+ guint total_csrc_count, idx, i;
+ GstRTPBuffer rtp = GST_RTP_BUFFER_INIT;
+
+ total_csrc_count = csrc_count + meta->csrc_count +
+ (meta->ssrc_valid ? 1 : 0);
+ total_csrc_count = MIN (total_csrc_count, 15);
+ buffer = gst_rtp_buffer_new_allocate (payload_len, pad_len,
+ total_csrc_count);
+
+ gst_rtp_buffer_map (buffer, GST_MAP_READWRITE, &rtp);
+
+ /* Skip CSRC fields requested by derived class and fill CSRCs from meta.
+ * Finally append the SSRC as a new CSRC. */
+ idx = csrc_count;
+ for (i = 0; i < meta->csrc_count && idx < 15; i++, idx++)
+ gst_rtp_buffer_set_csrc (&rtp, idx, meta->csrc[i]);
+ if (meta->ssrc_valid && idx < 15)
+ gst_rtp_buffer_set_csrc (&rtp, idx, meta->ssrc);
+
+ gst_rtp_buffer_unmap (&rtp);
+ }
+ }
+
+ if (buffer == NULL)
+ buffer = gst_rtp_buffer_new_allocate (payload_len, pad_len, csrc_count);
+
+ return buffer;
+}
+
static GstStructure *
gst_rtp_base_payload_create_stats (GstRTPBasePayload * rtpbasepayload)
{
case PROP_PTIME_MULTIPLE:
rtpbasepayload->ptime_multiple = g_value_get_int64 (value);
break;
+ case PROP_SOURCE_INFO:
+ gst_rtp_base_payload_set_source_info_enabled (rtpbasepayload,
+ g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_take_boxed (value,
gst_rtp_base_payload_create_stats (rtpbasepayload));
break;
+ case PROP_SOURCE_INFO:
+ g_value_set_boolean (value,
+ gst_rtp_base_payload_is_source_info_enabled (rtpbasepayload));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return ret;
}
+
+/**
+ * gst_rtp_base_payload_set_source_info_enabled:
+ * @payload: a #GstRTPBasePayload
+ * @enable: whether to add contributing sources to RTP packets
+ *
+ * Enable or disable adding contributing sources to RTP packets from
+ * #GstRTPSourceMeta.
+ *
+ * Since: 1.16
+ **/
+void
+gst_rtp_base_payload_set_source_info_enabled (GstRTPBasePayload * payload,
+ gboolean enable)
+{
+ payload->priv->source_info = enable;
+}
+
+/**
+ * gst_rtp_base_payload_is_source_info_enabled:
+ * @payload: a #GstRTPBasePayload
+ *
+ * Queries whether the payloader will add contributing sources (CSRCs) to the
+ * RTP header from #GstRTPSourceMeta.
+ *
+ * Returns: %TRUE if source-info is enabled.
+ *
+ * Since: 1.16
+ **/
+gboolean
+gst_rtp_base_payload_is_source_info_enabled (GstRTPBasePayload * payload)
+{
+ return payload->priv->source_info;
+}
+
+
+/**
+ * gst_rtp_base_payload_get_source_count:
+ * @payload: a #GstRTPBasePayload
+ * @buffer: (transfer none): a #GstBuffer, typically the buffer to payload
+ *
+ * Count the total number of RTP sources found in the meta of @buffer, which
+ * will be automically added by gst_rtp_base_payload_allocate_output_buffer().
+ * If #GstRTPBasePayload:source-info is %FALSE the count will be 0.
+ *
+ * Returns: The number of sources.
+ *
+ * Since: 1.16
+ **/
+guint
+gst_rtp_base_payload_get_source_count (GstRTPBasePayload * payload,
+ GstBuffer * buffer)
+{
+ guint count = 0;
+
+ g_return_val_if_fail (buffer != NULL, 0);
+
+ if (gst_rtp_base_payload_is_source_info_enabled (payload)) {
+ GstRTPSourceMeta *meta = gst_buffer_get_rtp_source_meta (buffer);
+ if (meta != NULL)
+ count = gst_rtp_source_meta_get_source_count (meta);
+ }
+
+ return count;
+}
GstFlowReturn gst_rtp_base_payload_push_list (GstRTPBasePayload *payload,
GstBufferList *list);
+GST_RTP_API
+GstBuffer * gst_rtp_base_payload_allocate_output_buffer (GstRTPBasePayload * payload,
+ guint payload_len, guint8 pad_len,
+ guint8 csrc_count);
+
+GST_RTP_API
+void gst_rtp_base_payload_set_source_info_enabled (GstRTPBasePayload * payload,
+ gboolean enable);
+
+GST_RTP_API
+gboolean gst_rtp_base_payload_is_source_info_enabled (GstRTPBasePayload * payload);
+
+GST_RTP_API
+guint gst_rtp_base_payload_get_source_count (GstRTPBasePayload * payload,
+ GstBuffer * buffer);
+
#ifdef G_DEFINE_AUTOPTR_CLEANUP_FUNC
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstRTPBasePayload, gst_object_unref)
#endif
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2016> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtpmeta.h"
+#include <string.h>
+
+/**
+ * SECTION:gstrtpmeta
+ * @title: GstMeta for RTP
+ * @short_description: RTP related GstMeta
+ *
+ */
+
+/**
+ * gst_buffer_add_rtp_source_meta:
+ * @buffer: a #GstBuffer
+ * @ssrc: (allow-none) (transfer none): pointer to the SSRC
+ * @csrc: (allow-none) (transfer none): pointer to the CSRCs
+ * @csrc_count: number of elements in @csrc
+ *
+ * Attaches RTP source information to @buffer.
+ *
+ * Returns: (transfer none): the #GstRTPSourceMeta on @buffer.
+ *
+ * Since: 1.16
+ */
+GstRTPSourceMeta *
+gst_buffer_add_rtp_source_meta (GstBuffer * buffer, const guint32 * ssrc,
+ const guint * csrc, guint csrc_count)
+{
+ gint i;
+ GstRTPSourceMeta *meta;
+
+ g_return_val_if_fail (buffer != NULL, NULL);
+ g_return_val_if_fail (csrc_count <= GST_RTP_SOURCE_META_MAX_CSRC_COUNT, NULL);
+ g_return_val_if_fail (csrc_count == 0 || csrc != NULL, NULL);
+
+ meta = (GstRTPSourceMeta *) gst_buffer_add_meta (buffer,
+ GST_RTP_SOURCE_META_INFO, NULL);
+ if (!meta)
+ return NULL;
+
+ if (ssrc != NULL) {
+ meta->ssrc = *ssrc;
+ meta->ssrc_valid = TRUE;
+ } else {
+ meta->ssrc_valid = FALSE;
+ }
+
+ meta->csrc_count = csrc_count;
+ for (i = 0; i < csrc_count; i++) {
+ meta->csrc[i] = csrc[i];
+ }
+
+ return meta;
+}
+
+/**
+ * gst_buffer_get_rtp_source_meta:
+ * @buffer: a #GstBuffer
+ *
+ * Find the #GstRTPSourceMeta on @buffer.
+ *
+ * Returns: (transfer none): the #GstRTPSourceMeta or %NULL when there
+ * is no such metadata on @buffer.
+ *
+ * Since: 1.16
+ */
+GstRTPSourceMeta *
+gst_buffer_get_rtp_source_meta (GstBuffer * buffer)
+{
+ return (GstRTPSourceMeta *) gst_buffer_get_meta (buffer,
+ gst_rtp_source_meta_api_get_type ());
+}
+
+static gboolean
+gst_rtp_source_meta_transform (GstBuffer * dst, GstMeta * meta,
+ GstBuffer * src, GQuark type, gpointer data)
+{
+ if (GST_META_TRANSFORM_IS_COPY (type)) {
+ GstRTPSourceMeta *smeta = (GstRTPSourceMeta *) meta;
+ GstRTPSourceMeta *dmeta;
+ guint32 *ssrc = smeta->ssrc_valid ? &smeta->ssrc : NULL;
+
+ dmeta = gst_buffer_add_rtp_source_meta (dst, ssrc, smeta->csrc,
+ smeta->csrc_count);
+ if (dmeta == NULL)
+ return FALSE;
+ } else {
+ /* return FALSE, if transform type is not supported */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_rtp_source_meta_get_source_count:
+ * @meta: a #GstRTPSourceMeta
+ *
+ * Count the total number of RTP sources found in @meta, both SSRC and CSRC.
+ *
+ * Returns: The number of RTP sources
+ *
+ * Since: 1.16
+ */
+guint
+gst_rtp_source_meta_get_source_count (const GstRTPSourceMeta * meta)
+{
+ /* Never return more than a count of 15 so that the returned value
+ * conveniently can be used as argument 'csrc_count' in
+ * gst_rtp_buffer-functions. */
+ guint ssrc_count = meta->ssrc_valid ? 1 : 0;
+ return MIN (meta->csrc_count + ssrc_count, 15);
+}
+
+/**
+ * gst_rtp_source_meta_set_ssrc:
+ * @meta: a #GstRTPSourceMeta
+ * @ssrc: (allow-none) (transfer none): pointer to the SSRC
+ *
+ * Sets @ssrc in @meta. If @ssrc is %NULL the ssrc of @meta will be unset.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 1.16
+ **/
+gboolean
+gst_rtp_source_meta_set_ssrc (GstRTPSourceMeta * meta, guint32 * ssrc)
+{
+ if (ssrc != NULL) {
+ meta->ssrc = *ssrc;
+ meta->ssrc_valid = TRUE;
+ } else {
+ meta->ssrc_valid = FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_rtp_source_meta_append_csrc:
+ * @meta: a #GstRTPSourceMeta
+ * @csrc: the csrcs to append
+ * @csrc_count: number of elements in @csrc
+ *
+ * Appends @csrc to the list of contributing sources in @meta.
+ *
+ * Returns: %TRUE if all elements in @csrc was added, %FALSE otherwise.
+ *
+ * Since: 1.16
+ **/
+gboolean
+gst_rtp_source_meta_append_csrc (GstRTPSourceMeta * meta, const guint32 * csrc,
+ guint csrc_count)
+{
+ gint i;
+ guint new_csrc_count = meta->csrc_count + csrc_count;
+
+ if (new_csrc_count > GST_RTP_SOURCE_META_MAX_CSRC_COUNT)
+ return FALSE;
+
+ for (i = 0; i < csrc_count; i++)
+ meta->csrc[meta->csrc_count + i] = csrc[i];
+ meta->csrc_count = new_csrc_count;
+
+ return TRUE;
+}
+
+GType
+gst_rtp_source_meta_api_get_type (void)
+{
+ static volatile GType type = 0;
+ static const gchar *tags[] = { NULL };
+
+ if (g_once_init_enter (&type)) {
+ GType _type = gst_meta_api_type_register ("GstRTPSourceMetaAPI", tags);
+ g_once_init_leave (&type, _type);
+ }
+ return type;
+}
+
+static gboolean
+gst_rtp_source_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
+{
+ GstRTPSourceMeta *dmeta = (GstRTPSourceMeta *) meta;
+
+ dmeta->ssrc_valid = FALSE;
+ dmeta->csrc_count = 0;
+
+ return TRUE;
+}
+
+const GstMetaInfo *
+gst_rtp_source_meta_get_info (void)
+{
+ static const GstMetaInfo *rtp_source_meta_info = NULL;
+
+ if (g_once_init_enter (&rtp_source_meta_info)) {
+ const GstMetaInfo *meta = gst_meta_register (GST_RTP_SOURCE_META_API_TYPE,
+ "GstRTPSourceMeta",
+ sizeof (GstRTPSourceMeta),
+ gst_rtp_source_meta_init,
+ (GstMetaFreeFunction) NULL,
+ gst_rtp_source_meta_transform);
+ g_once_init_leave (&rtp_source_meta_info, meta);
+ }
+ return rtp_source_meta_info;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2016> Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTP_META_H__
+#define __GST_RTP_META_H__
+
+#include <gst/gst.h>
+#include <gst/rtp/rtp-prelude.h>
+
+G_BEGIN_DECLS
+
+#define GST_RTP_SOURCE_META_API_TYPE (gst_rtp_source_meta_api_get_type())
+#define GST_RTP_SOURCE_META_INFO (gst_rtp_source_meta_get_info())
+typedef struct _GstRTPSourceMeta GstRTPSourceMeta;
+
+#define GST_RTP_SOURCE_META_MAX_CSRC_COUNT 15
+
+/**
+ * GstRTPSourceMeta:
+ * @meta: parent #GstMeta
+ * @ssrc: the SSRC
+ * @ssrc_valid: whether @ssrc is set and valid
+ * @csrc: (allow-none): pointer to the CSRCs
+ * @csrc_count: number of elements in @csrc
+ *
+ * Meta describing the source(s) of the buffer.
+ *
+ * Since: 1.16
+ */
+struct _GstRTPSourceMeta
+{
+ GstMeta meta;
+
+ guint32 ssrc;
+ gboolean ssrc_valid;
+ guint32 csrc[GST_RTP_SOURCE_META_MAX_CSRC_COUNT];
+ guint csrc_count;
+};
+
+GST_RTP_API
+GType gst_rtp_source_meta_api_get_type (void);
+
+GST_RTP_API
+GstRTPSourceMeta * gst_buffer_add_rtp_source_meta (GstBuffer * buf, const guint32 * ssrc,
+ const guint32 * csrc, guint csrc_count);
+GST_RTP_API
+GstRTPSourceMeta * gst_buffer_get_rtp_source_meta (GstBuffer * buf);
+
+GST_RTP_API
+guint gst_rtp_source_meta_get_source_count (const GstRTPSourceMeta * meta);
+
+GST_RTP_API
+gboolean gst_rtp_source_meta_set_ssrc (GstRTPSourceMeta * meta, guint32 * ssrc);
+
+GST_RTP_API
+gboolean gst_rtp_source_meta_append_csrc (GstRTPSourceMeta * meta,
+ const guint32 * csrc, guint csrc_count);
+GST_RTP_API
+const GstMetaInfo * gst_rtp_source_meta_get_info (void);
+
+G_END_DECLS
+
+#endif /* __GST_RTP_META_H__ */
'gstrtcpbuffer.c',
'gstrtppayloads.c',
'gstrtphdrext.c',
+ 'gstrtpmeta.c',
'gstrtpbaseaudiopayload.c',
'gstrtpbasepayload.c',
'gstrtpbasedepayload.c'
'gstrtpbuffer.h',
'gstrtpdefs.h',
'gstrtphdrext.h',
+ 'gstrtpmeta.h',
'gstrtppayloads.h',
'rtp-prelude.h',
'rtp.h',
#include <gst/rtp/gstrtpbaseaudiopayload.h>
#include <gst/rtp/gstrtpbasepayload.h>
#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/rtp/gstrtpmeta.h>
#include <gst/rtp/gstrtp-enumtypes.h>
#endif /* __GST_RTP_H__ */
libs/rtp \
libs/rtpbasedepayload \
libs/rtpbasepayload \
+ libs/rtpmeta \
libs/rtsp \
libs/rtspconnection \
libs/sdp \
$(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_API_VERSION@.la \
$(GST_BASE_LIBS) $(LDADD)
+libs_rtpmeta_CFLAGS = \
+ $(GST_PLUGINS_BASE_CFLAGS) \
+ $(AM_CFLAGS)
+libs_rtpmeta_LDADD = \
+ $(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_API_VERSION@.la \
+ $(GST_BASE_LIBS) $(LDADD)
+
libs_rtsp_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AM_CFLAGS)
rtp
rtpbasedepayload
rtpbasepayload
+rtpmeta
rtsp
rtspconnection
sdp
#include <gst/gst.h>
#include <gst/check/gstcheck.h>
-#include <gst/rtp/gstrtpbuffer.h>
-#include <gst/rtp/gstrtpbasedepayload.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/rtp.h>
#define DEFAULT_CLOCK_RATE (42)
va_end (var_args);
}
-#define push_rtp_buffer(state, field, ...) \
- push_rtp_buffer_full ((state), GST_FLOW_OK, (field), __VA_ARGS__)
-#define push_rtp_buffer_fails(state, error, field, ...) \
- push_rtp_buffer_full ((state), (error), (field), __VA_ARGS__)
-
static void
-push_rtp_buffer_full (State * state, GstFlowReturn expected,
- const gchar * field, ...)
+rtp_buffer_set_valist (GstBuffer * buf, const gchar * field, va_list var_args,
+ gboolean * extra_ref_)
{
- GstBuffer *buf = gst_rtp_buffer_new_allocate (0, 0, 0);
GstRTPBuffer rtp = { NULL };
gboolean mapped = FALSE;
gboolean extra_ref = FALSE;
- va_list var_args;
- va_start (var_args, field);
while (field) {
if (!g_strcmp0 (field, "pts")) {
GstClockTime pts = va_arg (var_args, GstClockTime);
gst_rtp_buffer_set_ssrc (&rtp, ssrc);
} else if (!g_strcmp0 (field, "extra-ref")) {
extra_ref = va_arg (var_args, gboolean);
+ if (extra_ref_)
+ *extra_ref_ = extra_ref;
+ } else if (!g_strcmp0 (field, "csrc")) {
+ guint idx = va_arg (var_args, guint);
+ guint csrc = va_arg (var_args, guint);
+ gst_rtp_buffer_set_csrc (&rtp, idx, csrc);
} else {
fail ("test cannot set unknown buffer field '%s'", field);
}
}
field = va_arg (var_args, const gchar *);
}
- va_end (var_args);
if (mapped) {
gst_rtp_buffer_unmap (&rtp);
if (extra_ref)
gst_buffer_ref (buf);
+}
+
+static void
+rtp_buffer_set (GstBuffer * buf, const gchar * field, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, field);
+ rtp_buffer_set_valist (buf, field, var_args, NULL);
+ va_end (var_args);
+}
+
+#define push_rtp_buffer(state, field, ...) \
+ push_rtp_buffer_full ((state), GST_FLOW_OK, (field), __VA_ARGS__)
+#define push_rtp_buffer_fails(state, error, field, ...) \
+ push_rtp_buffer_full ((state), (error), (field), __VA_ARGS__)
+
+static void
+push_rtp_buffer_full (State * state, GstFlowReturn expected,
+ const gchar * field, ...)
+{
+ GstBuffer *buf = gst_rtp_buffer_new_allocate (0, 0, 0);
+ va_list var_args;
+ gboolean extra_ref = FALSE;
+
+ va_start (var_args, field);
+ rtp_buffer_set_valist (buf, field, var_args, &extra_ref);
+ va_end (var_args);
fail_unless_equals_int (gst_pad_push (state->srcpad, buf), expected);
}
#define push_buffer(state, field, ...) \
- push_buffer_full ((state), GST_FLOW_OK, (field), __VA_ARGS__)
+ push_buffer_full ((state), GST_FLOW_OK, (field), __VA_ARGS__)
static void
push_buffer_full (State * state, GstFlowReturn expected,
destroy_depayloader (state);
}
-GST_END_TEST static Suite *
+GST_END_TEST
+/* basedepayloader has a property source-info that will add
+ * GstRTPSourceMeta to the output buffer with RTP source information, such as
+ * SSRC and CSRCs. The is useful for letting downstream know about the origin
+ * of the stream. */
+GST_START_TEST (rtp_base_depayload_source_info_test)
+{
+ GstHarness *h;
+ GstRtpDummyDepay *depay;
+ GstBuffer *buffer;
+ GstRTPSourceMeta *meta;
+ guint seq = 0;
+
+ depay = rtp_dummy_depay_new ();
+ h = gst_harness_new_with_element (GST_ELEMENT_CAST (depay), "sink", "src");
+ gst_harness_set_src_caps_str (h, "application/x-rtp");
+
+ /* Property enabled should always add meta, also when there is only SSRC and
+ * no CSRC. */
+ g_object_set (depay, "source-info", TRUE, NULL);
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ rtp_buffer_set (buffer, "seq", seq++, "ssrc", 0x11, NULL);
+ buffer = gst_harness_push_and_pull (h, buffer);
+ fail_unless ((meta = gst_buffer_get_rtp_source_meta (buffer)));
+ fail_unless (meta->ssrc_valid);
+ fail_unless_equals_int (meta->ssrc, 0x11);
+ fail_unless_equals_int (meta->csrc_count, 0);
+ gst_buffer_unref (buffer);
+
+ /* Both SSRC and CSRC should be added to the meta */
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 2);
+ rtp_buffer_set (buffer, "seq", seq++, "ssrc", 0x11, "csrc", 0, 0x22,
+ "csrc", 1, 0x33, NULL);
+ buffer = gst_harness_push_and_pull (h, buffer);
+ fail_unless ((meta = gst_buffer_get_rtp_source_meta (buffer)));
+ fail_unless (meta->ssrc_valid);
+ fail_unless_equals_int (meta->ssrc, 0x11);
+ fail_unless_equals_int (meta->csrc_count, 2);
+ fail_unless_equals_int (meta->csrc[0], 0x22);
+ fail_unless_equals_int (meta->csrc[1], 0x33);
+ gst_buffer_unref (buffer);
+
+ /* Property disabled should never add meta */
+ g_object_set (depay, "source-info", FALSE, NULL);
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ rtp_buffer_set (buffer, "seq", seq++, "ssrc", 0x11, NULL);
+ buffer = gst_harness_push_and_pull (h, buffer);
+ fail_if (gst_buffer_get_rtp_source_meta (buffer));
+ gst_buffer_unref (buffer);
+
+ g_object_unref (depay);
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
+
+static Suite *
rtp_basepayloading_suite (void)
{
Suite *s = suite_create ("rtp_base_depayloading_test");
tcase_add_test (tc_chain, rtp_base_depayload_play_speed_test);
tcase_add_test (tc_chain, rtp_base_depayload_clock_base_test);
+ tcase_add_test (tc_chain, rtp_base_depayload_source_info_test);
+
return s;
}
#include <gst/gst.h>
#include <gst/check/gstcheck.h>
-#include <gst/rtp/gstrtpbuffer.h>
-#include <gst/rtp/gstrtpbasepayload.h>
+#include <gst/check/gstharness.h>
+#include <gst/rtp/rtp.h>
#define DEFAULT_CLOCK_RATE (42)
#define BUFFER_BEFORE_LIST (10)
}
}
- paybuffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ paybuffer =
+ gst_rtp_base_payload_allocate_output_buffer (GST_RTP_BASE_PAYLOAD (pay),
+ 0, 0, 0);
GST_BUFFER_PTS (paybuffer) = GST_BUFFER_PTS (buffer);
GST_BUFFER_OFFSET (paybuffer) = GST_BUFFER_OFFSET (buffer);
}
static void
-validate_buffer (guint index, const gchar * field, ...)
+validate_buffer_valist (GstBuffer * buf, const gchar * field, va_list var_args)
{
- GstBuffer *buf;
GstRTPBuffer rtp = { NULL };
gboolean mapped = FALSE;
- va_list var_args;
-
- fail_if (index >= g_list_length (buffers));
- buf = GST_BUFFER (g_list_nth_data (buffers, index));
- fail_if (buf == NULL);
- GST_TRACE ("%" GST_PTR_FORMAT, buf);
-
- va_start (var_args, field);
while (field) {
if (!g_strcmp0 (field, "pts")) {
GstClockTime pts = va_arg (var_args, GstClockTime);
} else if (!g_strcmp0 (field, "ssrc")) {
guint32 ssrc = va_arg (var_args, guint);
fail_unless_equals_int (gst_rtp_buffer_get_ssrc (&rtp), ssrc);
+ } else if (!g_strcmp0 (field, "csrc")) {
+ guint idx = va_arg (var_args, guint);
+ guint csrc = va_arg (var_args, guint);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc (&rtp, idx), csrc);
+ } else if (!g_strcmp0 (field, "csrc-count")) {
+ guint csrc_count = va_arg (var_args, guint);
+ fail_unless_equals_int (gst_rtp_buffer_get_csrc_count (&rtp),
+ csrc_count);
} else {
fail ("test cannot validate unknown buffer field '%s'", field);
}
}
field = va_arg (var_args, const gchar *);
}
- va_end (var_args);
if (mapped) {
gst_rtp_buffer_unmap (&rtp);
}
static void
+validate_buffer1 (GstBuffer * buf, const gchar * field, ...)
+{
+ va_list var_args;
+
+ va_start (var_args, field);
+ validate_buffer_valist (buf, field, var_args);
+ va_end (var_args);
+}
+
+static void
+validate_buffer (guint index, const gchar * field, ...)
+{
+ GstBuffer *buf;
+ va_list var_args;
+
+ fail_if (index >= g_list_length (buffers));
+ buf = GST_BUFFER (g_list_nth_data (buffers, index));
+ fail_if (buf == NULL);
+
+ GST_TRACE ("%" GST_PTR_FORMAT, buf);
+
+ va_start (var_args, field);
+ validate_buffer_valist (buf, field, var_args);
+ va_end (var_args);
+}
+
+static void
get_buffer_field (guint index, const gchar * field, ...)
{
GstBuffer *buf;
GST_END_TEST;
+/* basepayloader has a property source-info that makes it aware of RTP
+ * source information passed as GstRTPSourceMeta on the input buffers. All
+ * sources found in the meta will be added to the list of CSRCs in the RTP
+ * header. A useful scenario for this is, for instance, to signal which
+ * sources contributed to a mixed audio stream. */
+GST_START_TEST (rtp_base_payload_property_source_info_test)
+{
+ GstHarness *h;
+ GstRtpDummyPay *pay;
+ GstBuffer *buffer;
+ guint csrc_count = 2;
+ const guint32 csrc[] = { 0x11, 0x22 };
+ const guint32 ssrc = 0x33;
+
+ pay = rtp_dummy_pay_new ();
+ h = gst_harness_new_with_element (GST_ELEMENT_CAST (pay), "sink", "src");
+ gst_harness_set_src_caps_str (h, "application/x-rtp");
+
+ /* Input buffer has no meta, payloader should not add CSRC */
+ g_object_set (pay, "source-info", TRUE, NULL);
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ buffer = gst_harness_push_and_pull (h, buffer);
+ validate_buffer1 (buffer, "csrc-count", 0, NULL);
+ fail_if (gst_buffer_get_rtp_source_meta (buffer));
+ gst_buffer_unref (buffer);
+
+ /* Input buffer has meta, payloader should add CSRC */
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ fail_unless (gst_buffer_add_rtp_source_meta (buffer, &ssrc, csrc,
+ csrc_count));
+ buffer = gst_harness_push_and_pull (h, buffer);
+ /* The meta SSRC should be added as the last contributing source */
+ validate_buffer1 (buffer, "csrc-count", 3, "csrc", 0, csrc[0],
+ "csrc", 1, csrc[1], "csrc", 2, ssrc, NULL);
+ fail_if (gst_buffer_get_rtp_source_meta (buffer));
+ gst_buffer_unref (buffer);
+
+ /* When property is disabled, the meta should be ignored and no CSRC
+ * added. */
+ g_object_set (pay, "source-info", FALSE, NULL);
+ buffer = gst_rtp_buffer_new_allocate (0, 0, 0);
+ fail_unless (gst_buffer_add_rtp_source_meta (buffer, NULL, csrc, csrc_count));
+ buffer = gst_harness_push_and_pull (h, buffer);
+ validate_buffer1 (buffer, "csrc-count", 0, NULL);
+ fail_if (gst_buffer_get_rtp_source_meta (buffer));
+ gst_buffer_unref (buffer);
+
+ g_object_unref (pay);
+ gst_harness_teardown (h);
+}
+
+GST_END_TEST;
+
/* push a single buffer to the payloader which should successfully payload it
* into an RTP packet. besides the payloaded RTP packet there should be the
* three events initial events: stream-start, caps and segment. because of that
tcase_add_test (tc_chain, rtp_base_payload_property_perfect_rtptime_test);
tcase_add_test (tc_chain, rtp_base_payload_property_ptime_multiple_test);
tcase_add_test (tc_chain, rtp_base_payload_property_stats_test);
+ tcase_add_test (tc_chain, rtp_base_payload_property_source_info_test);
tcase_add_test (tc_chain, rtp_base_payload_framerate_attribute);
tcase_add_test (tc_chain, rtp_base_payload_max_framerate_attribute);
--- /dev/null
+/* GStreamer RTP meta unit tests
+ * Copyright (C) 2016 Stian Selnes <stian@pexip.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General
+ * Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/check/gstcheck.h>
+#include <gst/rtp/rtp.h>
+
+GST_START_TEST (test_rtp_source_meta_set_get_sources)
+{
+ GstBuffer *buffer;
+ GstRTPSourceMeta *meta;
+ guint32 ssrc = 1000, ssrc2 = 2000;
+ const guint32 csrc[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+ };
+
+ buffer = gst_buffer_new ();
+ meta = gst_buffer_add_rtp_source_meta (buffer, &ssrc, csrc, 12);
+
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 12 + 1);
+ fail_unless (meta->ssrc_valid);
+ fail_unless_equals_int (meta->ssrc, ssrc);
+ for (gint i = 0; i < 12; i++)
+ fail_unless_equals_int (meta->csrc[i], csrc[i]);
+
+ /* Unset the ssrc */
+ fail_unless (gst_rtp_source_meta_set_ssrc (meta, NULL));
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 12);
+ fail_if (meta->ssrc_valid);
+
+ /* Set the ssrc again */
+ fail_unless (gst_rtp_source_meta_set_ssrc (meta, &ssrc2));
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 12 + 1);
+ fail_unless (meta->ssrc_valid);
+ fail_unless_equals_int (meta->ssrc, ssrc2);
+
+ /* Append multiple csrcs */
+ fail_unless (gst_rtp_source_meta_append_csrc (meta, &csrc[12], 2));
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 14 + 1);
+ for (gint i = 0; i < 14; i++)
+ fail_unless_equals_int (meta->csrc[i], csrc[i]);
+
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtp_source_meta_set_get_max_sources)
+{
+ GstBuffer *buffer;
+ GstRTPSourceMeta *meta;
+ guint32 ssrc = 1000;
+ const guint32 csrc[16] = { 0, };
+
+ buffer = gst_buffer_new ();
+ meta = gst_buffer_add_rtp_source_meta (buffer, &ssrc, csrc, 14);
+
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 14 + 1);
+ fail_unless_equals_int (meta->csrc_count, 14);
+ fail_unless (meta->ssrc_valid);
+ fail_unless_equals_int (meta->ssrc, ssrc);
+
+ /* Append one more csrc */
+ /* The source count should cap at 15 for convenient use with
+ * gst_rtp_buffer-functions! */
+ fail_unless (gst_rtp_source_meta_append_csrc (meta, &csrc[14], 1));
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 15);
+ fail_unless_equals_int (meta->csrc_count, 15);
+
+ /* Try to append one more csrc, but we've reached max */
+ fail_if (gst_rtp_source_meta_append_csrc (meta, &csrc[15], 1));
+ fail_unless_equals_int (gst_rtp_source_meta_get_source_count (meta), 15);
+ fail_unless_equals_int (meta->csrc_count, 15);
+
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+static Suite *
+rtp_meta_suite (void)
+{
+ Suite *s = suite_create ("rtp_meta_tests");
+ TCase *tc_chain;
+
+ suite_add_tcase (s, (tc_chain = tcase_create ("GstRTPSourceMeta")));
+ tcase_add_test (tc_chain, test_rtp_source_meta_set_get_sources);
+ tcase_add_test (tc_chain, test_rtp_source_meta_set_get_max_sources);
+
+ return s;
+}
+
+GST_CHECK_MAIN (rtp_meta)