plugin_LTLIBRARIES = libgstavtp.la
-libgstavtp_la_SOURCES = gstavtp.c
+libgstavtp_la_SOURCES = \
+ gstavtp.c \
+ gstavtpaafpay.c \
+ gstavtpbasepayload.c
libgstavtp_la_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(AVTP_CFLAGS)
libgstavtp_la_LIBADD = \
- $(GST_PLUGINS_BASE_LIBS) \
+ $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(AVTP_LIBS)
libgstavtp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = \
+ gstavtpaafpay.h \
+ gstavtpbasepayload.h
*
* If libavtp isn't detected by configure, the plugin isn't built.
*
+ * ### The application/x-avtp mime type
+ *
+ * For valid AVTPDUs encapsulated in GstBuffers, we use the caps with mime type
+ * application/x-avtp.
+ *
+ * AVTP mime type is pretty simple and has no fields.
+ *
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#include <gst/gst.h>
+#include "gstavtpaafpay.h"
+
static gboolean
plugin_init (GstPlugin * plugin)
{
+ if (!gst_avtp_aaf_pay_plugin_init (plugin))
+ return FALSE;
+
return TRUE;
}
--- /dev/null
+/*
+ * GStreamer AVTP Plugin
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-avtpaafpay
+ * @see_also: avtpaafdepay
+ *
+ * Payload raw audio into AVTPDUs according to IEEE 1722-2016. For detailed
+ * information see https://standards.ieee.org/standard/1722-2016.html.
+ *
+ * <refsect2>
+ * <title>Example pipeline</title>
+ * |[
+ * gst-launch-1.0 audiotestsrc ! audioconvert ! avtpaafpay ! avtpsink
+ * ]| This example pipeline will payload raw audio. Refer to the avtpaafdepay
+ * example to depayload and play the AVTP stream.
+ * </refsect2>
+ */
+
+#include <avtp.h>
+#include <avtp_aaf.h>
+#include <gst/audio/audio-format.h>
+
+#include "gstavtpaafpay.h"
+
+GST_DEBUG_CATEGORY_STATIC (avtpaafpay_debug);
+#define GST_CAT_DEFAULT (avtpaafpay_debug)
+
+#define DEFAULT_TSTAMP_MODE GST_AVTP_AAF_TSTAMP_MODE_NORMAL
+
+enum
+{
+ PROP_0,
+ PROP_TSTAMP_MODE,
+};
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) { S16BE, S24BE, S32BE, F32BE }, "
+ "rate = (int) { 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000 }, "
+ "channels = " GST_AUDIO_CHANNELS_RANGE ", "
+ "layout = (string) interleaved")
+ );
+
+#define GST_TYPE_AVTP_AAF_TSTAMP_MODE (gst_avtp_aaf_tstamp_mode_get_type())
+static GType
+gst_avtp_aaf_tstamp_mode_get_type (void)
+{
+ static GType tstamp_mode_type = 0;
+ static const GEnumValue tstamp_mode_types[] = {
+ {GST_AVTP_AAF_TSTAMP_MODE_NORMAL, "Normal timestamping mode", "normal"},
+ {GST_AVTP_AAF_TSTAMP_MODE_SPARSE, "Sparse timestamping mode", "sparse"},
+ {0, NULL, NULL},
+ };
+
+ tstamp_mode_type =
+ g_enum_register_static ("GstAvtpAafTstampMode", tstamp_mode_types);
+
+ return tstamp_mode_type;
+}
+
+#define gst_avtp_aaf_pay_parent_class parent_class
+G_DEFINE_TYPE (GstAvtpAafPay, gst_avtp_aaf_pay, GST_TYPE_AVTP_BASE_PAYLOAD);
+
+static void gst_avtp_aaf_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_avtp_aaf_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static GstStateChangeReturn gst_avtp_aaf_pay_change_state (GstElement * element,
+ GstStateChange transition);
+
+static GstFlowReturn gst_avtp_aaf_pay_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static gboolean gst_avtp_aaf_pay_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
+
+static void
+gst_avtp_aaf_pay_class_init (GstAvtpAafPayClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstAvtpBasePayloadClass *avtpbasepayload_class =
+ GST_AVTP_BASE_PAYLOAD_CLASS (klass);
+
+ object_class->set_property = gst_avtp_aaf_pay_set_property;
+ object_class->get_property = gst_avtp_aaf_pay_get_property;
+
+ g_object_class_install_property (object_class, PROP_TSTAMP_MODE,
+ g_param_spec_enum ("tstamp-mode", "Timestamping Mode",
+ "AAF timestamping mode", GST_TYPE_AVTP_AAF_TSTAMP_MODE,
+ DEFAULT_TSTAMP_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_PAUSED));
+
+ element_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_avtp_aaf_pay_change_state);
+
+ gst_element_class_add_static_pad_template (element_class, &sink_template);
+
+ gst_element_class_set_static_metadata (element_class,
+ "AVTP Audio Format (AAF) payloader",
+ "Codec/Payloader/Network/AVTP",
+ "Payload-encode Raw audio into AAF AVTPDU (IEEE 1722)",
+ "Andre Guedes <andre.guedes@intel.com>");
+
+ avtpbasepayload_class->chain = GST_DEBUG_FUNCPTR (gst_avtp_aaf_pay_chain);
+ avtpbasepayload_class->sink_event =
+ GST_DEBUG_FUNCPTR (gst_avtp_aaf_pay_sink_event);
+
+ GST_DEBUG_CATEGORY_INIT (avtpaafpay_debug, "avtpaafpay", 0,
+ "AAF AVTP Payloader");
+}
+
+static void
+gst_avtp_aaf_pay_init (GstAvtpAafPay * avtpaafpay)
+{
+ avtpaafpay->tstamp_mode = DEFAULT_TSTAMP_MODE;
+
+ avtpaafpay->header = NULL;
+ avtpaafpay->channels = 0;
+ avtpaafpay->depth = 0;
+ avtpaafpay->rate = 0;
+ avtpaafpay->format = 0;
+}
+
+static void
+gst_avtp_aaf_pay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstAvtpAafPay *avtpaafpay = GST_AVTP_AAF_PAY (object);
+
+ GST_DEBUG_OBJECT (avtpaafpay, "prop_id %u", prop_id);
+
+ switch (prop_id) {
+ case PROP_TSTAMP_MODE:
+ avtpaafpay->tstamp_mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_avtp_aaf_pay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstAvtpAafPay *avtpaafpay = GST_AVTP_AAF_PAY (object);
+
+ GST_DEBUG_OBJECT (avtpaafpay, "prop_id %u", prop_id);
+
+ switch (prop_id) {
+ case PROP_TSTAMP_MODE:
+ g_value_set_enum (value, avtpaafpay->tstamp_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstStateChangeReturn
+gst_avtp_aaf_pay_change_state (GstElement * element, GstStateChange transition)
+{
+ GstStateChangeReturn ret;
+ GstAvtpAafPay *avtpaafpay = GST_AVTP_AAF_PAY (element);
+
+ GST_DEBUG_OBJECT (avtpaafpay, "transition %d", transition);
+
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:{
+ GstMemory *mem;
+
+ mem = gst_allocator_alloc (NULL, sizeof (struct avtp_stream_pdu), NULL);
+ if (!mem) {
+ GST_ERROR_OBJECT (avtpaafpay, "Failed to allocate GstMemory");
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ avtpaafpay->header = gst_memory_ref (mem);
+ break;
+ }
+ case GST_STATE_CHANGE_READY_TO_PAUSED:{
+ int res;
+ GstMapInfo info;
+ struct avtp_stream_pdu *pdu;
+ GstMemory *mem = avtpaafpay->header;
+ GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (element);
+
+ if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) {
+ GST_ERROR_OBJECT (avtpaafpay, "Failed to map GstMemory");
+ return GST_STATE_CHANGE_FAILURE;
+ }
+ pdu = (struct avtp_stream_pdu *) info.data;
+ res = avtp_aaf_pdu_init (pdu);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_MR, 0);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TV, 1);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TU, 0);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_ID,
+ avtpbasepayload->streamid);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_SP, avtpaafpay->tstamp_mode);
+ g_assert (res == 0);
+ gst_memory_unmap (mem, &info);
+ break;
+ }
+ default:
+ break;
+ }
+
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE) {
+ GST_ERROR_OBJECT (avtpaafpay, "Parent failed to handle state transition");
+ return ret;
+ }
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ gst_memory_unref (avtpaafpay->header);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_avtp_aaf_pay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
+{
+ int res;
+ GstMemory *mem;
+ GstMapInfo info;
+ gsize data_len;
+ GstClockTime ptime;
+ struct avtp_stream_pdu *pdu;
+ GstAvtpAafPay *avtpaafpay = GST_AVTP_AAF_PAY (parent);
+ GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (parent);
+
+ ptime = gst_avtp_base_payload_calc_ptime (avtpbasepayload, buffer);
+ data_len = gst_buffer_get_size (buffer);
+
+ mem = gst_memory_copy (avtpaafpay->header, 0, -1);
+ if (!gst_memory_map (mem, &info, GST_MAP_WRITE)) {
+ GST_ELEMENT_ERROR (avtpaafpay, RESOURCE, WRITE, ("Failed to map memory"),
+ (NULL));
+ gst_buffer_unref (buffer);
+ return GST_FLOW_ERROR;
+ }
+ pdu = (struct avtp_stream_pdu *) info.data;
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_TIMESTAMP, ptime);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_NSR, avtpaafpay->rate);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_FORMAT, avtpaafpay->format);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_BIT_DEPTH, avtpaafpay->depth);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, data_len);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME,
+ avtpaafpay->channels);
+ g_assert (res == 0);
+ res = avtp_aaf_pdu_set (pdu, AVTP_AAF_FIELD_SEQ_NUM,
+ avtpbasepayload->seqnum++);
+ g_assert (res == 0);
+ gst_memory_unmap (mem, &info);
+
+ gst_buffer_prepend_memory (buffer, mem);
+ return gst_pad_push (avtpbasepayload->srcpad, buffer);
+}
+
+static int
+gst_to_avtp_rate (gint rate)
+{
+ switch (rate) {
+ case 8000:
+ return AVTP_AAF_PCM_NSR_8KHZ;
+ case 16000:
+ return AVTP_AAF_PCM_NSR_16KHZ;
+ case 24000:
+ return AVTP_AAF_PCM_NSR_24KHZ;
+ case 32000:
+ return AVTP_AAF_PCM_NSR_32KHZ;
+ case 44100:
+ return AVTP_AAF_PCM_NSR_44_1KHZ;
+ case 48000:
+ return AVTP_AAF_PCM_NSR_48KHZ;
+ case 88200:
+ return AVTP_AAF_PCM_NSR_88_2KHZ;
+ case 96000:
+ return AVTP_AAF_PCM_NSR_96KHZ;
+ case 176400:
+ return AVTP_AAF_PCM_NSR_176_4KHZ;
+ case 192000:
+ return AVTP_AAF_PCM_NSR_192KHZ;
+ default:
+ return AVTP_AAF_PCM_NSR_USER;
+ }
+}
+
+static int
+gst_to_avtp_format (GstAudioFormat format)
+{
+ switch (format) {
+ case GST_AUDIO_FORMAT_S16BE:
+ return AVTP_AAF_FORMAT_INT_16BIT;
+ case GST_AUDIO_FORMAT_S24BE:
+ return AVTP_AAF_FORMAT_INT_24BIT;
+ case GST_AUDIO_FORMAT_S32BE:
+ return AVTP_AAF_FORMAT_INT_32BIT;
+ case GST_AUDIO_FORMAT_F32BE:
+ return AVTP_AAF_FORMAT_FLOAT_32BIT;
+ default:
+ return AVTP_AAF_FORMAT_USER;
+ }
+}
+
+static gboolean
+gst_avtp_aaf_pay_new_caps (GstAvtpAafPay * avtpaafpay, GstCaps * caps)
+{
+ GstAudioInfo info;
+
+ gst_audio_info_init (&info);
+ if (!gst_audio_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (avtpaafpay, "Failed to get info from caps");
+ return FALSE;
+ }
+
+ avtpaafpay->channels = info.channels;
+ avtpaafpay->depth = info.finfo->depth;
+ avtpaafpay->rate = gst_to_avtp_rate (info.rate);
+ avtpaafpay->format = gst_to_avtp_format (info.finfo->format);
+
+ GST_DEBUG_OBJECT (avtpaafpay, "channels %d, depth %d, rate %d, format %s",
+ info.channels, info.finfo->depth, info.rate,
+ gst_audio_format_to_string (info.finfo->format));
+ return TRUE;
+}
+
+static gboolean
+gst_avtp_aaf_pay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
+{
+ GstCaps *caps;
+ GstAvtpAafPay *avtpaafpay = GST_AVTP_AAF_PAY (parent);
+
+ GST_DEBUG_OBJECT (avtpaafpay, "event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ gst_event_parse_caps (event, &caps);
+ return gst_avtp_aaf_pay_new_caps (avtpaafpay, caps);
+ default:
+ return GST_AVTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (pad,
+ parent, event);
+ }
+}
+
+gboolean
+gst_avtp_aaf_pay_plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "avtpaafpay", GST_RANK_NONE,
+ GST_TYPE_AVTP_AAF_PAY);
+}
--- /dev/null
+/*
+ * GStreamer AVTP Plugin
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_AVTP_AAF_PAY_H__
+#define __GST_AVTP_AAF_PAY_H__
+
+#include <gst/gst.h>
+
+#include "gstavtpbasepayload.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AVTP_AAF_PAY (gst_avtp_aaf_pay_get_type())
+#define GST_AVTP_AAF_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVTP_AAF_PAY,GstAvtpAafPay))
+#define GST_AVTP_AAF_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVTP_AAF_PAY,GstAvtpAafPayClass))
+#define GST_IS_AVTP_AAF_PAY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVTP_AAF_PAY))
+#define GST_IS_AVTP_AAF_PAY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVTP_AAF_PAY))
+
+typedef struct _GstAvtpAafPay GstAvtpAafPay;
+typedef struct _GstAvtpAafPayClass GstAvtpAafPayClass;
+typedef enum _GstAvtpAafTstampMode GstAvtpAafTstampMode;
+
+enum _GstAvtpAafTstampMode {
+ GST_AVTP_AAF_TSTAMP_MODE_NORMAL,
+ GST_AVTP_AAF_TSTAMP_MODE_SPARSE,
+};
+
+struct _GstAvtpAafPay
+{
+ GstAvtpBasePayload payload;
+
+ GstAvtpAafTstampMode tstamp_mode;
+
+ GstMemory *header;
+ gint channels;
+ gint depth;
+ gint rate;
+ gint format;
+};
+
+struct _GstAvtpAafPayClass
+{
+ GstAvtpBasePayloadClass parent_class;
+};
+
+GType gst_avtp_aaf_pay_get_type (void);
+
+gboolean gst_avtp_aaf_pay_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_AVTP_AAF_PAY_H__ */
--- /dev/null
+/*
+ * GStreamer AVTP Plugin
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gstavtpbasepayload.h"
+
+GST_DEBUG_CATEGORY_STATIC (avtpbasepayload_debug);
+#define GST_CAT_DEFAULT (avtpbasepayload_debug)
+
+#define DEFAULT_STREAMID 0xAABBCCDDEEFF0000
+#define DEFAULT_MTT 50000000
+#define DEFAULT_TU 1000000
+#define DEFAULT_PROCESSING_DEADLINE (20 * GST_MSECOND)
+
+enum
+{
+ PROP_0,
+ PROP_STREAMID,
+ PROP_MTT,
+ PROP_TU,
+ PROP_PROCESSING_DEADLINE,
+};
+
+static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("application/x-avtp")
+ );
+
+static void gst_avtp_base_payload_class_init (GstAvtpBasePayloadClass * klass);
+static void gst_avtp_base_payload_init (GstAvtpBasePayload * avtpbasepayload,
+ gpointer g_class);
+
+static void gst_avtp_base_payload_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_avtp_base_payload_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean gst_avtp_base_payload_sink_event (GstPad * pad,
+ GstObject * parent, GstEvent * event);
+
+GType
+gst_avtp_base_payload_get_type (void)
+{
+ static GType avtpbasepayload_type = 0;
+
+ if (g_once_init_enter ((gsize *) & avtpbasepayload_type)) {
+ static const GTypeInfo avtpbasepayload_info = {
+ sizeof (GstAvtpBasePayloadClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gst_avtp_base_payload_class_init,
+ NULL,
+ NULL,
+ sizeof (GstAvtpBasePayload),
+ 0,
+ (GInstanceInitFunc) gst_avtp_base_payload_init,
+ };
+ GType _type;
+
+ _type = g_type_register_static (GST_TYPE_ELEMENT, "GstAvtpBasePayload",
+ &avtpbasepayload_info, G_TYPE_FLAG_ABSTRACT);
+
+ g_once_init_leave ((gsize *) & avtpbasepayload_type, _type);
+ }
+ return avtpbasepayload_type;
+}
+
+static void
+gst_avtp_base_payload_class_init (GstAvtpBasePayloadClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = gst_avtp_base_payload_set_property;
+ object_class->get_property = gst_avtp_base_payload_get_property;
+
+ g_object_class_install_property (object_class, PROP_STREAMID,
+ g_param_spec_uint64 ("streamid", "Stream ID",
+ "Stream ID associated with the AVTPDU", 0, G_MAXUINT64,
+ DEFAULT_STREAMID, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+ g_object_class_install_property (object_class, PROP_MTT,
+ g_param_spec_uint ("mtt", "Maximum Transit Time",
+ "Maximum Transit Time (MTT) in nanoseconds", 0,
+ G_MAXUINT, DEFAULT_MTT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_TU,
+ g_param_spec_uint ("tu", "Timing Uncertainty",
+ "Timing Uncertainty (TU) in nanoseconds", 0,
+ G_MAXUINT, DEFAULT_TU, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (object_class, PROP_PROCESSING_DEADLINE,
+ g_param_spec_uint64 ("processing-deadline", "Processing deadline",
+ "Maximum amount of time (in ns) the pipeline can take for processing the buffer",
+ 0, G_MAXUINT64, DEFAULT_PROCESSING_DEADLINE, G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ klass->chain = NULL;
+ klass->sink_event = GST_DEBUG_FUNCPTR (gst_avtp_base_payload_sink_event);
+
+ GST_DEBUG_CATEGORY_INIT (avtpbasepayload_debug, "avtpbasepayload", 0,
+ "Base class for AVTP payloaders");
+}
+
+static void
+gst_avtp_base_payload_init (GstAvtpBasePayload * avtpbasepayload,
+ gpointer g_class)
+{
+ GstPadTemplate *templ;
+ GstElement *element = GST_ELEMENT (avtpbasepayload);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstAvtpBasePayloadClass *avtpbasepayload_class =
+ GST_AVTP_BASE_PAYLOAD_CLASS (g_class);
+
+ g_assert (avtpbasepayload_class->chain != NULL);
+
+ avtpbasepayload->srcpad = gst_pad_new_from_static_template (&src_template,
+ "src");
+ gst_element_add_pad (element, avtpbasepayload->srcpad);
+
+ templ = gst_element_class_get_pad_template (element_class, "sink");
+ g_assert (templ != NULL);
+ avtpbasepayload->sinkpad = gst_pad_new_from_template (templ, "sink");
+ gst_pad_set_chain_function (avtpbasepayload->sinkpad,
+ avtpbasepayload_class->chain);
+ gst_pad_set_event_function (avtpbasepayload->sinkpad,
+ avtpbasepayload_class->sink_event);
+ gst_element_add_pad (element, avtpbasepayload->sinkpad);
+
+ avtpbasepayload->streamid = DEFAULT_STREAMID;
+ avtpbasepayload->mtt = DEFAULT_MTT;
+ avtpbasepayload->tu = DEFAULT_TU;
+ avtpbasepayload->processing_deadline = DEFAULT_PROCESSING_DEADLINE;
+
+ avtpbasepayload->latency = GST_CLOCK_TIME_NONE;
+ avtpbasepayload->seqnum = 0;
+ gst_segment_init (&avtpbasepayload->segment, GST_FORMAT_UNDEFINED);
+}
+
+static void
+gst_avtp_base_payload_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (object);
+
+ GST_DEBUG_OBJECT (avtpbasepayload, "prop_id %u", prop_id);
+
+ switch (prop_id) {
+ case PROP_STREAMID:
+ avtpbasepayload->streamid = g_value_get_uint64 (value);
+ break;
+ case PROP_MTT:
+ avtpbasepayload->mtt = g_value_get_uint (value);
+ break;
+ case PROP_TU:
+ avtpbasepayload->tu = g_value_get_uint (value);
+ break;
+ case PROP_PROCESSING_DEADLINE:
+ avtpbasepayload->processing_deadline = g_value_get_uint64 (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_avtp_base_payload_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (object);
+
+ GST_DEBUG_OBJECT (avtpbasepayload, "prop_id %u", prop_id);
+
+ switch (prop_id) {
+ case PROP_STREAMID:
+ g_value_set_uint64 (value, avtpbasepayload->streamid);
+ break;
+ case PROP_MTT:
+ g_value_set_uint (value, avtpbasepayload->mtt);
+ break;
+ case PROP_TU:
+ g_value_set_uint (value, avtpbasepayload->tu);
+ break;
+ case PROP_PROCESSING_DEADLINE:
+ g_value_set_uint64 (value, avtpbasepayload->processing_deadline);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static gboolean
+gst_avtp_base_payload_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (parent);
+
+ GST_DEBUG_OBJECT (avtpbasepayload, "event %s", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ gst_event_copy_segment (event, &avtpbasepayload->segment);
+ /* Fall through */
+ default:
+ return gst_pad_event_default (pad, parent, event);
+ }
+}
+
+GstClockTime
+gst_avtp_base_payload_calc_ptime (GstAvtpBasePayload * avtpbasepayload,
+ GstBuffer * buffer)
+{
+ GstClockTime base_time, running_time;
+
+ g_assert (GST_BUFFER_PTS (buffer) != GST_CLOCK_TIME_NONE);
+
+ if (G_UNLIKELY (avtpbasepayload->latency == GST_CLOCK_TIME_NONE)) {
+ GstQuery *query;
+
+ query = gst_query_new_latency ();
+ if (!gst_pad_peer_query (avtpbasepayload->sinkpad, query))
+ return GST_CLOCK_TIME_NONE;
+ gst_query_parse_latency (query, NULL, &avtpbasepayload->latency, NULL);
+ gst_query_unref (query);
+
+ GST_DEBUG_OBJECT (avtpbasepayload, "latency %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (avtpbasepayload->latency));
+ }
+
+ base_time = gst_element_get_base_time (GST_ELEMENT (avtpbasepayload));
+
+ running_time = gst_segment_to_running_time (&avtpbasepayload->segment,
+ avtpbasepayload->segment.format, GST_BUFFER_PTS (buffer));
+
+ return base_time + running_time + avtpbasepayload->latency +
+ avtpbasepayload->processing_deadline + avtpbasepayload->mtt +
+ avtpbasepayload->tu;
+}
--- /dev/null
+/*
+ * GStreamer AVTP Plugin
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_AVTP_BASE_PAYLOAD_H__
+#define __GST_AVTP_BASE_PAYLOAD_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AVTP_BASE_PAYLOAD (gst_avtp_base_payload_get_type())
+#define GST_AVTP_BASE_PAYLOAD(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVTP_BASE_PAYLOAD,GstAvtpBasePayload))
+#define GST_AVTP_BASE_PAYLOAD_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVTP_BASE_PAYLOAD,GstAvtpBasePayloadClass))
+#define GST_IS_AVTP_BASE_PAYLOAD(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVTP_BASE_PAYLOAD))
+#define GST_IS_AVTP_BASE_PAYLOAD_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVTP_BASE_PAYLOAD))
+
+typedef struct _GstAvtpBasePayload GstAvtpBasePayload;
+typedef struct _GstAvtpBasePayloadClass GstAvtpBasePayloadClass;
+
+struct _GstAvtpBasePayload
+{
+ GstElement element;
+
+ GstPad *sinkpad;
+ GstPad *srcpad;
+
+ guint64 streamid;
+ guint mtt;
+ guint tu;
+ guint64 processing_deadline;
+
+ GstClockTime latency;
+ GstSegment segment;
+ guint8 seqnum;
+
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _GstAvtpBasePayloadClass
+{
+ GstElementClass parent_class;
+
+ /* Pure virtual function. */
+ GstPadChainFunction chain;
+
+ GstPadEventFunction sink_event;
+
+ gpointer _gst_reserved[GST_PADDING];
+};
+
+GType gst_avtp_base_payload_get_type (void);
+
+GstClockTime gst_avtp_base_payload_calc_ptime (GstAvtpBasePayload *
+ avtpbasepayload, GstBuffer * buffer);
+
+G_END_DECLS
+
+#endif /* __GST_AVTP_BASE_PAYLOAD_H__ */
avtp_sources = [
'gstavtp.c',
+ 'gstavtpaafpay.c',
+ 'gstavtpbasepayload.c',
]
avtp_dep = dependency('avtp', required: get_option('avtp'))
avtp_sources,
c_args : gst_plugins_bad_args,
include_directories : [configinc],
- dependencies : libavtp_dep,
+ dependencies : [gstaudio_dep, avtp_dep],
install : true,
install_dir : plugins_install_dir,
)