From 3b4f3a0b3f2985681f86572607f38173407f8a1f Mon Sep 17 00:00:00 2001 From: Ederson de Souza Date: Thu, 28 Feb 2019 15:49:02 -0800 Subject: avtp: Introduce AVTP CVF payloader element This patch introduces the AVTP Compressed Video Format (CVF) payloader specified in IEEE 1722-2016 section 8. Currently, this payload only supports H.264 encapsulation described in section 8.5. Is also worth noting that only single NAL units are encapsulated: no aggregation or fragmentation is performed by the payloader. An interesting characteristic of CVF H.264 spec is that it defines an H264_TIMESTAMP, in addition to the AVTP timestamp. The later is translated to the GST_BUFFER_DTS while the former is translated to the GST_BUFFER_PTS. From AVTP CVF H.264 spec, it is clear that the AVTP timestamp is related to the decoding order, while the H264_TIMESTAMP is an ancillary information to the H.264 decoder. Upon receiving a buffer containing a group of NAL units, the avtpcvfpay element will extract each NAL unit and payload them into individual AVTP packets. The last AVTP packet generated for a group of NAL units will have the M bit set, so the depayloader is able to properly regroup them. The exact format of the buffer of NAL units is described on the 'codec_data' capability, which is parsed by the avtpcvfpay, in the same way done in rtph264pay. This patch reuses the infra provided by gstavtpbasepayload.c. --- ext/avtp/Makefile.am | 2 + ext/avtp/gstavtp.c | 3 + ext/avtp/gstavtpcvfpay.c | 484 +++++++++++++++++++++++++++++++++++++++++++++++ ext/avtp/gstavtpcvfpay.h | 66 +++++++ ext/avtp/meson.build | 3 +- 5 files changed, 557 insertions(+), 1 deletion(-) create mode 100644 ext/avtp/gstavtpcvfpay.c create mode 100644 ext/avtp/gstavtpcvfpay.h (limited to 'ext/avtp') diff --git a/ext/avtp/Makefile.am b/ext/avtp/Makefile.am index db6fe4892..1d3eb5bbc 100644 --- a/ext/avtp/Makefile.am +++ b/ext/avtp/Makefile.am @@ -6,6 +6,7 @@ libgstavtp_la_SOURCES = \ gstavtpaafpay.c \ gstavtpbasedepayload.c \ gstavtpbasepayload.c \ + gstavtpcvfpay.c \ gstavtpsink.c \ gstavtpsrc.c @@ -28,5 +29,6 @@ noinst_HEADERS = \ gstavtpaafpay.h \ gstavtpbasedepayload.h \ gstavtpbasepayload.h \ + gstavtpcvfpay.h \ gstavtpsink.h \ gstavtpsrc.h diff --git a/ext/avtp/gstavtp.c b/ext/avtp/gstavtp.c index c0d15bf79..c077eb4a3 100644 --- a/ext/avtp/gstavtp.c +++ b/ext/avtp/gstavtp.c @@ -52,6 +52,7 @@ #include "gstavtpaafdepay.h" #include "gstavtpaafpay.h" +#include "gstavtpcvfpay.h" #include "gstavtpsink.h" #include "gstavtpsrc.h" @@ -66,6 +67,8 @@ plugin_init (GstPlugin * plugin) return FALSE; if (!gst_avtp_src_plugin_init (plugin)) return FALSE; + if (!gst_avtp_cvf_pay_plugin_init (plugin)) + return FALSE; return TRUE; } diff --git a/ext/avtp/gstavtpcvfpay.c b/ext/avtp/gstavtpcvfpay.c new file mode 100644 index 000000000..b131d6a93 --- /dev/null +++ b/ext/avtp/gstavtpcvfpay.c @@ -0,0 +1,484 @@ +/* + * 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-avtpcvfpay + * @see_also: avtpcvfdepay + * + * Payload compressed video (currently, only H.264) into AVTPDUs according + * to IEEE 1722-2016. For detailed information see + * https://standards.ieee.org/standard/1722-2016.html. + * + * + * Example pipeline + * |[ + * gst-launch-1.0 videotestsrc ! x264enc ! avtpcvfpay ! avtpsink + * ]| This example pipeline will payload H.264 video. Refer to the avtpcvfdepay + * example to depayload and play the AVTP stream. + * + */ + +#include +#include + +#include "gstavtpcvfpay.h" + +GST_DEBUG_CATEGORY_STATIC (avtpcvfpay_debug); +#define GST_CAT_DEFAULT avtpcvfpay_debug + +/* prototypes */ + +static GstFlowReturn gst_avtp_cvf_pay_chain (GstPad * pad, GstObject * parent, + GstBuffer * buffer); +static gboolean gst_avtp_cvf_pay_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); + +static void gst_avtp_cvf_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_avtp_cvf_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstStateChangeReturn gst_avtp_cvf_change_state (GstElement * + element, GstStateChange transition); + +enum +{ + PROP_0, + PROP_MTU +}; + +#define DEFAULT_MTU 1500 + +#define AVTP_CVF_H264_HEADER_SIZE (sizeof(struct avtp_stream_pdu) + sizeof(guint32)) + +#define NAL_TYPE_MASK 0x1f +#define FIRST_NAL_VCL_TYPE 0x01 +#define LAST_NAL_VCL_TYPE 0x05 +#define NAL_LEN_SIZE_MASK 0x03 + +/* pad templates */ + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-h264, " + "stream-format = (string) avc, alignment = (string) au") + ); + +/* class initialization */ + +#define gst_avtp_cvf_pay_parent_class parent_class +G_DEFINE_TYPE (GstAvtpCvfPay, gst_avtp_cvf_pay, GST_TYPE_AVTP_BASE_PAYLOAD); + +static void +gst_avtp_cvf_pay_class_init (GstAvtpCvfPayClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); + GstAvtpBasePayloadClass *avtpbasepayload_class = + GST_AVTP_BASE_PAYLOAD_CLASS (klass); + + gst_element_class_add_static_pad_template (gstelement_class, &sink_template); + + gst_element_class_set_static_metadata (gstelement_class, + "AVTP Compressed Video Format (CVF) payloader", + "Codec/Payloader/Network/AVTP", + "Payload-encode compressed video into CVF AVTPDU (IEEE 1722)", + "Ederson de Souza "); + + gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_avtp_cvf_set_property); + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_avtp_cvf_get_property); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_avtp_cvf_change_state); + + avtpbasepayload_class->chain = GST_DEBUG_FUNCPTR (gst_avtp_cvf_pay_chain); + avtpbasepayload_class->sink_event = + GST_DEBUG_FUNCPTR (gst_avtp_cvf_pay_sink_event); + + g_object_class_install_property (gobject_class, PROP_MTU, + g_param_spec_uint ("mtu", "Maximum Transit Unit", + "Maximum Transit Unit (MTU) of underlying network in bytes", 0, + G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + GST_DEBUG_CATEGORY_INIT (avtpcvfpay_debug, "avtpcvfpay", + 0, "debug category for avtpcvfpay element"); +} + +static void +gst_avtp_cvf_pay_init (GstAvtpCvfPay * avtpcvfpay) +{ + avtpcvfpay->mtu = DEFAULT_MTU; + avtpcvfpay->header = NULL; + avtpcvfpay->nal_length_size = 0; +} + +static void +gst_avtp_cvf_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstAvtpCvfPay *avtpcvfpay = GST_AVTP_CVF_PAY (object); + + GST_DEBUG_OBJECT (avtpcvfpay, "prop_id: %u", prop_id); + + if (prop_id == PROP_MTU) { + avtpcvfpay->mtu = g_value_get_uint (value); + } else { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gst_avtp_cvf_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstAvtpCvfPay *avtpcvfpay = GST_AVTP_CVF_PAY (object); + + GST_DEBUG_OBJECT (avtpcvfpay, "prop_id: %u", prop_id); + + if (prop_id == PROP_MTU) { + g_value_set_uint (value, avtpcvfpay->mtu); + } else { + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static GstStateChangeReturn +gst_avtp_cvf_change_state (GstElement * element, GstStateChange transition) +{ + GstAvtpCvfPay *avtpcvfpay = GST_AVTP_CVF_PAY (element); + GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (avtpcvfpay); + GstStateChangeReturn ret; + + if (transition == GST_STATE_CHANGE_NULL_TO_READY) { + GstMapInfo map; + struct avtp_stream_pdu *pdu; + int res; + + avtpcvfpay->header = gst_buffer_new_allocate (NULL, + AVTP_CVF_H264_HEADER_SIZE, NULL); + if (avtpcvfpay->header == NULL) { + GST_ERROR_OBJECT (avtpcvfpay, "Could not allocate buffer"); + return GST_STATE_CHANGE_FAILURE; + } + + gst_buffer_map (avtpcvfpay->header, &map, GST_MAP_WRITE); + pdu = (struct avtp_stream_pdu *) map.data; + + res = avtp_cvf_pdu_init (pdu, AVTP_CVF_FORMAT_SUBTYPE_H264); + g_assert (res == 0); + res = avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TV, 1); + g_assert (res == 0); + res = + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_ID, + avtpbasepayload->streamid); + g_assert (res == 0); + + gst_buffer_unmap (avtpcvfpay->header, &map); + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) { + return ret; + } + + if (transition == GST_STATE_CHANGE_READY_TO_NULL) { + gst_buffer_unref (avtpcvfpay->header); + } + + return ret; +} + +static void +gst_avtp_cvf_pay_extract_nals (GstAvtpCvfPay * avtpcvfpay, + GstBuffer * buffer, GPtrArray * nals) +{ + /* The buffer may have more than one NAL. They are grouped together, and before + * each NAL there are some bytes that indicate how big is the NAL */ + + gsize size, offset = 0; + GstMapInfo map; + guint8 *data; + gboolean res; + + if (G_UNLIKELY (avtpcvfpay->nal_length_size == 0)) { + GST_ERROR_OBJECT (avtpcvfpay, + "Can't extract NAL units without nal length size. Missing codec_data caps?"); + goto end; + } + + res = gst_buffer_map (buffer, &map, GST_MAP_READ); + if (!res) { + GST_ERROR_OBJECT (avtpcvfpay, "Could map buffer"); + goto end; + } + + size = map.size; + data = map.data; + + while (size > avtpcvfpay->nal_length_size) { + gint i; + guint nal_len = 0; + GstBuffer *nal; + + /* Gets NAL length */ + for (i = 0; i < avtpcvfpay->nal_length_size; i++) { + nal_len = (nal_len << 8) + data[i]; + } + + offset += avtpcvfpay->nal_length_size; + data += avtpcvfpay->nal_length_size; + size -= avtpcvfpay->nal_length_size; + + if (G_UNLIKELY (size < nal_len)) { + GST_WARNING_OBJECT (avtpcvfpay, + "Got incomplete NAL: NAL len %u, buffer len %zu", nal_len, size); + nal_len = size; + } + + nal = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, offset, nal_len); + GST_BUFFER_PTS (nal) = GST_BUFFER_PTS (buffer); + GST_BUFFER_DTS (nal) = GST_BUFFER_DTS (buffer); + g_ptr_array_add (nals, nal); + + offset += nal_len; + data += nal_len; + size -= nal_len; + } + + gst_buffer_unmap (buffer, &map); + +end: + /* This function consumes the buffer, and all references to it are in the + * extracted nals, so we can release the reference to the buffer itself */ + gst_buffer_unref (buffer); + + GST_LOG_OBJECT (avtpcvfpay, "Extracted %u NALu's from buffer", nals->len); +} + +static gboolean +gst_avtp_cvf_pay_is_nal_vcl (GstAvtpCvfPay * avtpcvfpay, GstBuffer * nal) +{ + guint8 nal_header, nal_type; + + gst_buffer_extract (nal, 0, &nal_header, 1); + nal_type = nal_header & NAL_TYPE_MASK; + + return nal_type >= FIRST_NAL_VCL_TYPE && nal_type <= LAST_NAL_VCL_TYPE; +} + +static gboolean +gst_avtp_cvf_pay_prepare_avtp_packets (GstAvtpCvfPay * avtpcvfpay, + GPtrArray * nals, GPtrArray * avtp_packets) +{ + GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (avtpcvfpay); + GstBuffer *header, *packet, *nal; + GstMapInfo map; + gint i; + + for (i = 0; i < nals->len; i++) { + int res; + struct avtp_stream_pdu *pdu; + guint64 avtp_time, h264_time; + + /* Copy saved header to reuse common fields and change what is needed */ + header = gst_buffer_copy (avtpcvfpay->header); + gst_buffer_map (header, &map, GST_MAP_WRITE); + pdu = (struct avtp_stream_pdu *) map.data; + + nal = g_ptr_array_index (nals, i); + GST_LOG_OBJECT (avtpcvfpay, + "Preparing AVTP packet for NAL whose size is %lu", + gst_buffer_get_size (nal)); + + /* Calculate timestamps. Note that we do it twice, one using DTS as base, + * the other using PTS - using code inherited from avtpbasepayload. + * Also worth noting: `avtpbasepayload->latency` is updated after + * first call to gst_avtp_base_payload_calc_ptime, so we MUST call + * it before using the latency value */ + h264_time = gst_avtp_base_payload_calc_ptime (avtpbasepayload, nal); + + avtp_time = + gst_element_get_base_time (GST_ELEMENT (avtpcvfpay)) + + gst_segment_to_running_time (&avtpbasepayload->segment, GST_FORMAT_TIME, + GST_BUFFER_DTS_OR_PTS (nal)) + avtpbasepayload->mtt + + avtpbasepayload->tu + avtpbasepayload->processing_deadline + + avtpbasepayload->latency; + + res = avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_TIMESTAMP, avtp_time); + g_assert (res == 0); + res = + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_SEQ_NUM, + avtpbasepayload->seqnum++); + g_assert (res == 0); + + /* Set M only if last NAL and it is a VCL NAL */ + res = avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_M, + i == nals->len - 1 && gst_avtp_cvf_pay_is_nal_vcl (avtpcvfpay, nal)); + g_assert (res == 0); + + /* Stream data len includes AVTP H264 header len as this is part of + * the payload too. It's just the uint32_t with the h264 timestamp*/ + res = + avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_STREAM_DATA_LEN, + gst_buffer_get_size (nal) + sizeof (uint32_t)); + g_assert (res == 0); + + res = avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_TIMESTAMP, h264_time); + g_assert (res == 0); + + res = avtp_cvf_pdu_set (pdu, AVTP_CVF_FIELD_H264_PTV, 1); + g_assert (res == 0); + /* TODO check if NALs can be grouped, or need to be + * fragmented */ + + gst_buffer_unmap (header, &map); + packet = gst_buffer_append (header, nal); + + g_ptr_array_add (avtp_packets, packet); + } + + GST_LOG_OBJECT (avtpcvfpay, "Prepared %u AVTP packets", avtp_packets->len); + + return TRUE; +} + +static gboolean +gst_avtp_cvf_pay_push_packets (GstAvtpCvfPay * avtpcvfpay, + GPtrArray * avtp_packets) +{ + int i; + GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (avtpcvfpay); + + for (i = 0; i < avtp_packets->len; i++) { + GstBuffer *packet; + + packet = g_ptr_array_index (avtp_packets, i); + if (gst_pad_push (avtpbasepayload->srcpad, packet) != GST_FLOW_OK) + return FALSE; + } + + return TRUE; +} + +static GstFlowReturn +gst_avtp_cvf_pay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) +{ + GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (parent); + GstAvtpCvfPay *avtpcvfpay = GST_AVTP_CVF_PAY (avtpbasepayload); + GPtrArray *nals, *avtp_packets; + GstFlowReturn ret = GST_FLOW_OK; + + GST_LOG_OBJECT (avtpcvfpay, + "Incoming buffer size: %lu PTS: %" GST_TIME_FORMAT " DTS: %" + GST_TIME_FORMAT, gst_buffer_get_size (buffer), + GST_TIME_ARGS (GST_BUFFER_PTS (buffer)), + GST_TIME_ARGS (GST_BUFFER_DTS (buffer))); + + /* Get all NALs inside buffer */ + nals = g_ptr_array_new (); + gst_avtp_cvf_pay_extract_nals (avtpcvfpay, buffer, nals); + + /* Prepare a list of avtp_packets to send */ + avtp_packets = g_ptr_array_new (); + gst_avtp_cvf_pay_prepare_avtp_packets (avtpcvfpay, nals, avtp_packets); + + if (!gst_avtp_cvf_pay_push_packets (avtpcvfpay, avtp_packets)) + ret = GST_FLOW_ERROR; + + /* Contents of both ptr_arrays should be unref'd or transferred + * to rightful owner by this point, no need to unref them again */ + g_ptr_array_free (nals, TRUE); + g_ptr_array_free (avtp_packets, TRUE); + + return ret; +} + +static gboolean +gst_avtp_cvf_pay_new_caps (GstAvtpCvfPay * avtpcvfpay, GstCaps * caps) +{ + const GValue *value; + GstStructure *str; + GstBuffer *buffer; + GstMapInfo map; + + str = gst_caps_get_structure (caps, 0); + + if ((value = gst_structure_get_value (str, "codec_data"))) { + guint8 *data; + gsize size; + + buffer = gst_value_get_buffer (value); + gst_buffer_map (buffer, &map, GST_MAP_READ); + data = map.data; + size = map.size; + + if (G_UNLIKELY (size < 7)) { + GST_ERROR_OBJECT (avtpcvfpay, "avcC size %" G_GSIZE_FORMAT " < 7", size); + goto error; + } + if (G_UNLIKELY (data[0] != 1)) { + GST_ERROR_OBJECT (avtpcvfpay, "avcC version %u != 1", data[0]); + goto error; + } + + /* Number of bytes in front of NAL units marking their size */ + avtpcvfpay->nal_length_size = (data[4] & NAL_LEN_SIZE_MASK) + 1; + GST_DEBUG_OBJECT (avtpcvfpay, "Got NAL length from caps: %u", + avtpcvfpay->nal_length_size); + + gst_buffer_unmap (buffer, &map); + } + + return TRUE; + +error: + gst_buffer_unmap (buffer, &map); + return FALSE; +} + +static gboolean +gst_avtp_cvf_pay_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstCaps *caps; + GstAvtpBasePayload *avtpbasepayload = GST_AVTP_BASE_PAYLOAD (parent); + GstAvtpCvfPay *avtpcvfpay = GST_AVTP_CVF_PAY (avtpbasepayload); + + GST_DEBUG_OBJECT (avtpcvfpay, "Sink 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_cvf_pay_new_caps (avtpcvfpay, caps); + default: + break; + } + + return GST_AVTP_BASE_PAYLOAD_CLASS (parent_class)->sink_event (pad, parent, + event); +} + +gboolean +gst_avtp_cvf_pay_plugin_init (GstPlugin * plugin) +{ + return gst_element_register (plugin, "avtpcvfpay", GST_RANK_NONE, + GST_TYPE_AVTP_CVF_PAY); +} diff --git a/ext/avtp/gstavtpcvfpay.h b/ext/avtp/gstavtpcvfpay.h new file mode 100644 index 000000000..cd9d98738 --- /dev/null +++ b/ext/avtp/gstavtpcvfpay.h @@ -0,0 +1,66 @@ +/* + * 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_CVF_PAY_H__ +#define __GST_AVTP_CVF_PAY_H__ + +#include + +#include "gstavtpbasepayload.h" + +G_BEGIN_DECLS + +#define GST_TYPE_AVTP_CVF_PAY (gst_avtp_cvf_pay_get_type()) +#define GST_AVTP_CVF_PAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVTP_CVF_PAY,GstAvtpCvfPay)) +#define GST_AVTP_CVF_PAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVTP_CVF_PAY,GstAvtpCvfPayClass)) +#define GST_IS_AVTP_CVF_PAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVTP_CVF_PAY)) +#define GST_IS_AVTP_CVF_PAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVTP_CVF_PAY)) + +typedef struct _GstAvtpCvfPay GstAvtpCvfPay; +typedef struct _GstAvtpCvfPayClass GstAvtpCvfPayClass; + +struct _GstAvtpCvfPay +{ + GstAvtpBasePayload payload; + + GstBuffer *header; + guint mtu; + + /* H.264 specific information */ + guint8 nal_length_size; +}; + +struct _GstAvtpCvfPayClass +{ + GstAvtpBasePayloadClass parent_class; +}; + +GType gst_avtp_cvf_pay_get_type (void); + +gboolean gst_avtp_cvf_pay_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_AVTP_CVF_PAY_H__ */ diff --git a/ext/avtp/meson.build b/ext/avtp/meson.build index ba843a13e..2eb3347d4 100644 --- a/ext/avtp/meson.build +++ b/ext/avtp/meson.build @@ -2,6 +2,7 @@ avtp_sources = [ 'gstavtp.c', 'gstavtpaafdepay.c', 'gstavtpaafpay.c', + 'gstavtpcvfpay.c', 'gstavtpbasedepayload.c', 'gstavtpbasepayload.c', 'gstavtpsink.c', @@ -15,7 +16,7 @@ if avtp_dep.found() avtp_sources, c_args : gst_plugins_bad_args, include_directories : [configinc], - dependencies : [gstaudio_dep, avtp_dep], + dependencies : [gstaudio_dep, gstvideo_dep, avtp_dep], install : true, install_dir : plugins_install_dir, ) -- cgit v1.2.1