mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-26 18:20:44 +00:00
256 lines
8.4 KiB
C
256 lines
8.4 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");
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|