gstreamer/subprojects/gst-plugins-bad/ext/avtp/gstavtpbasepayload.c

258 lines
8.5 KiB
C

/*
* 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");
gst_type_mark_as_plugin_api (GST_TYPE_AVTP_BASE_PAYLOAD, 0);
}
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;
}