• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer AVTP Plugin
3  * Copyright (C) 2019 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later
9  * version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301 USA
20  */
21 
22 /**
23  * SECTION:element-avtpaafdepay
24  * @see_also: avtpaafpay
25  *
26  * Extract raw audio from AVTPDUs according to IEEE 1722-2016. For detailed
27  * information see https://standards.ieee.org/standard/1722-2016.html.
28  *
29  * <refsect2>
30  * <title>Example pipeline</title>
31  * |[
32  * gst-launch-1.0 avtpsrc ! avtpaafdepay ! autoaudiosink
33  * ]| This example pipeline will depayload AVTPDUs. Refer to the avtpaafpay
34  * example to create the AVTP stream.
35  * </refsect2>
36  */
37 
38 #include <avtp.h>
39 #include <avtp_aaf.h>
40 #include <gst/audio/audio-format.h>
41 
42 #include "gstavtpaafdepay.h"
43 
44 GST_DEBUG_CATEGORY_STATIC (avtpaafdepay_debug);
45 #define GST_CAT_DEFAULT (avtpaafdepay_debug)
46 
47 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
48     GST_PAD_SRC,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS ("audio/x-raw, "
51         "format = (string) { S16BE, S24BE, S32BE, F32BE }, "
52         "rate = (int) { 8000, 16000, 24000, 32000, 44100, 48000, 88200, 96000, 176400, 192000 }, "
53         "channels = " GST_AUDIO_CHANNELS_RANGE ", "
54         "layout = (string) interleaved")
55     );
56 
57 G_DEFINE_TYPE (GstAvtpAafDepay, gst_avtp_aaf_depay,
58     GST_TYPE_AVTP_BASE_DEPAYLOAD);
59 GST_ELEMENT_REGISTER_DEFINE (avtpaafdepay, "avtpaafdepay", GST_RANK_NONE,
60     GST_TYPE_AVTP_AAF_DEPAY);
61 
62 static GstFlowReturn gst_avtp_aaf_depay_chain (GstPad * pad, GstObject * parent,
63     GstBuffer * buffer);
64 
65 static void
gst_avtp_aaf_depay_class_init(GstAvtpAafDepayClass * klass)66 gst_avtp_aaf_depay_class_init (GstAvtpAafDepayClass * klass)
67 {
68   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
69   GstAvtpBaseDepayloadClass *avtpbasedepayload_class =
70       GST_AVTP_BASE_DEPAYLOAD_CLASS (klass);
71 
72   gst_element_class_add_static_pad_template (element_class, &src_template);
73 
74   gst_element_class_set_static_metadata (element_class,
75       "AVTP Audio Format (AAF) depayloader",
76       "Codec/Depayloader/Network/AVTP",
77       "Extracts raw audio from AAF AVTPDUs",
78       "Andre Guedes <andre.guedes@intel.com>");
79 
80   avtpbasedepayload_class->chain = GST_DEBUG_FUNCPTR (gst_avtp_aaf_depay_chain);
81 
82   GST_DEBUG_CATEGORY_INIT (avtpaafdepay_debug, "avtpaafdepay", 0,
83       "AAF AVTP Depayloader");
84 }
85 
86 static void
gst_avtp_aaf_depay_init(GstAvtpAafDepay * avtpaafdepay)87 gst_avtp_aaf_depay_init (GstAvtpAafDepay * avtpaafdepay)
88 {
89   avtpaafdepay->channels = 0;
90   avtpaafdepay->depth = 0;
91   avtpaafdepay->rate = 0;
92   avtpaafdepay->format = 0;
93 }
94 
95 static const gchar *
avtp_to_gst_format(int avtp_format)96 avtp_to_gst_format (int avtp_format)
97 {
98   GstAudioFormat gst_format;
99 
100   switch (avtp_format) {
101     case AVTP_AAF_FORMAT_INT_16BIT:
102       gst_format = GST_AUDIO_FORMAT_S16BE;
103       break;
104     case AVTP_AAF_FORMAT_INT_24BIT:
105       gst_format = GST_AUDIO_FORMAT_S24BE;
106       break;
107     case AVTP_AAF_FORMAT_INT_32BIT:
108       gst_format = GST_AUDIO_FORMAT_S32BE;
109       break;
110     case AVTP_AAF_FORMAT_FLOAT_32BIT:
111       gst_format = GST_AUDIO_FORMAT_F32BE;
112       break;
113     default:
114       gst_format = GST_AUDIO_FORMAT_UNKNOWN;
115       break;
116   }
117 
118   return gst_audio_format_to_string (gst_format);
119 }
120 
121 static gint
avtp_to_gst_rate(int rate)122 avtp_to_gst_rate (int rate)
123 {
124   switch (rate) {
125     case AVTP_AAF_PCM_NSR_8KHZ:
126       return 8000;
127     case AVTP_AAF_PCM_NSR_16KHZ:
128       return 16000;
129     case AVTP_AAF_PCM_NSR_24KHZ:
130       return 24000;
131     case AVTP_AAF_PCM_NSR_32KHZ:
132       return 32000;
133     case AVTP_AAF_PCM_NSR_44_1KHZ:
134       return 44100;
135     case AVTP_AAF_PCM_NSR_48KHZ:
136       return 48000;
137     case AVTP_AAF_PCM_NSR_88_2KHZ:
138       return 88200;
139     case AVTP_AAF_PCM_NSR_96KHZ:
140       return 96000;
141     case AVTP_AAF_PCM_NSR_176_4KHZ:
142       return 176400;
143     case AVTP_AAF_PCM_NSR_192KHZ:
144       return 192000;
145     default:
146       return 0;
147   }
148 }
149 
150 static gboolean
gst_avtp_aaf_depay_push_caps_event(GstAvtpAafDepay * avtpaafdepay,gint rate,gint depth,gint format,gint channels)151 gst_avtp_aaf_depay_push_caps_event (GstAvtpAafDepay * avtpaafdepay,
152     gint rate, gint depth, gint format, gint channels)
153 {
154   GstCaps *caps;
155   GstEvent *event;
156   GstAvtpBaseDepayload *avtpbasedepayload =
157       GST_AVTP_BASE_DEPAYLOAD (avtpaafdepay);
158 
159   caps = gst_caps_new_simple ("audio/x-raw",
160       "format", G_TYPE_STRING, avtp_to_gst_format (format),
161       "rate", G_TYPE_INT, avtp_to_gst_rate (rate),
162       "channels", G_TYPE_INT, channels,
163       "layout", G_TYPE_STRING, "interleaved", NULL);
164 
165   event = gst_event_new_caps (caps);
166 
167   if (!gst_pad_push_event (avtpbasedepayload->srcpad, event)) {
168     GST_ERROR_OBJECT (avtpaafdepay, "Failed to push CAPS event");
169     gst_caps_unref (caps);
170     return FALSE;
171   }
172 
173   GST_DEBUG_OBJECT (avtpaafdepay, "CAPS event pushed %" GST_PTR_FORMAT, caps);
174 
175   avtpaafdepay->rate = rate;
176   avtpaafdepay->depth = depth;
177   avtpaafdepay->format = format;
178   avtpaafdepay->channels = channels;
179   gst_caps_unref (caps);
180   return TRUE;
181 }
182 
183 static gboolean
gst_avtp_aaf_depay_are_audio_features_valid(GstAvtpAafDepay * avtpaafdepay,guint64 rate,guint64 depth,guint64 format,guint64 channels)184 gst_avtp_aaf_depay_are_audio_features_valid (GstAvtpAafDepay * avtpaafdepay,
185     guint64 rate, guint64 depth, guint64 format, guint64 channels)
186 {
187   if (G_UNLIKELY (rate != avtpaafdepay->rate)) {
188     GST_INFO_OBJECT (avtpaafdepay, "Rate doesn't match, disarding buffer");
189     return FALSE;
190   }
191   if (G_UNLIKELY (depth != avtpaafdepay->depth)) {
192     GST_INFO_OBJECT (avtpaafdepay, "Bit depth doesn't match, disarding buffer");
193     return FALSE;
194   }
195   if (G_UNLIKELY (format != avtpaafdepay->format)) {
196     GST_INFO_OBJECT (avtpaafdepay,
197         "Sample format doesn't match, disarding buffer");
198     return FALSE;
199   }
200   if (G_UNLIKELY (channels != avtpaafdepay->channels)) {
201     GST_INFO_OBJECT (avtpaafdepay,
202         "Number of channels doesn't match, disarding buffer");
203     return FALSE;
204   }
205 
206   return TRUE;
207 }
208 
209 static GstFlowReturn
gst_avtp_aaf_depay_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)210 gst_avtp_aaf_depay_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
211 {
212   int res;
213   GstMapInfo info;
214   guint32 subtype, version;
215   GstClockTime ptime;
216   GstBuffer *subbuffer;
217   struct avtp_stream_pdu *pdu;
218   guint64 channels, depth, rate, format, tstamp, seqnum, streamid,
219       streamid_valid, data_len;
220   GstAvtpBaseDepayload *avtpbasedepayload = GST_AVTP_BASE_DEPAYLOAD (parent);
221   GstAvtpAafDepay *avtpaafdepay = GST_AVTP_AAF_DEPAY (avtpbasedepayload);
222 
223   if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
224     GST_ELEMENT_ERROR (avtpaafdepay, RESOURCE, READ, ("Failed to map memory"),
225         (NULL));
226     gst_buffer_unref (buffer);
227     return GST_FLOW_ERROR;
228   }
229 
230   if (info.size < sizeof (struct avtp_stream_pdu)) {
231     GST_DEBUG_OBJECT (avtpaafdepay, "Malformed AVTPDU, discarding it");
232     gst_buffer_unmap (buffer, &info);
233     goto discard;
234   }
235 
236   pdu = (struct avtp_stream_pdu *) info.data;
237   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_NSR, &rate);
238   g_assert (res == 0);
239   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_FORMAT, &format);
240   g_assert (res == 0);
241   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_SEQ_NUM, &seqnum);
242   g_assert (res == 0);
243   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_BIT_DEPTH, &depth);
244   g_assert (res == 0);
245   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_TIMESTAMP, &tstamp);
246   g_assert (res == 0);
247   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_SV, &streamid_valid);
248   g_assert (res == 0);
249   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_STREAM_ID, &streamid);
250   g_assert (res == 0);
251   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_CHAN_PER_FRAME, &channels);
252   g_assert (res == 0);
253   res = avtp_aaf_pdu_get (pdu, AVTP_AAF_FIELD_STREAM_DATA_LEN, &data_len);
254   g_assert (res == 0);
255   res = avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_SUBTYPE,
256       &subtype);
257   g_assert (res == 0);
258   res = avtp_pdu_get ((struct avtp_common_pdu *) pdu, AVTP_FIELD_VERSION,
259       &version);
260   g_assert (res == 0);
261 
262   gst_buffer_unmap (buffer, &info);
263 
264   if (subtype != AVTP_SUBTYPE_AAF) {
265     GST_DEBUG_OBJECT (avtpaafdepay, "Subtype doesn't match, discarding buffer");
266     goto discard;
267   }
268   if (version != 0) {
269     GST_DEBUG_OBJECT (avtpaafdepay, "Version doesn't match, discarding buffer");
270     goto discard;
271   }
272   if (streamid_valid != 1 || streamid != avtpbasedepayload->streamid) {
273     GST_DEBUG_OBJECT (avtpaafdepay, "Invalid StreamID, discarding buffer");
274     goto discard;
275   }
276   if (gst_buffer_get_size (buffer) < sizeof (*pdu) + data_len) {
277     GST_DEBUG_OBJECT (avtpaafdepay, "Incomplete AVTPDU, discarding buffer");
278     goto discard;
279   }
280 
281   if (G_UNLIKELY (!gst_pad_has_current_caps (avtpbasedepayload->srcpad))) {
282     if (!gst_avtp_aaf_depay_push_caps_event (avtpaafdepay, rate, depth, format,
283             channels)) {
284       gst_buffer_unref (buffer);
285       return GST_FLOW_NOT_NEGOTIATED;
286     }
287     if (!gst_avtp_base_depayload_push_segment_event (avtpbasedepayload, tstamp)) {
288       gst_buffer_unref (buffer);
289       return GST_FLOW_ERROR;
290     }
291 
292     avtpbasedepayload->seqnum = seqnum;
293   }
294 
295   if (G_UNLIKELY (!gst_avtp_aaf_depay_are_audio_features_valid (avtpaafdepay,
296               rate, depth, format, channels)))
297     goto discard;
298 
299   if (seqnum != avtpbasedepayload->seqnum) {
300     GST_INFO_OBJECT (avtpaafdepay, "Sequence number mismatch: expected %u"
301         " received %" G_GUINT64_FORMAT, avtpbasedepayload->seqnum, seqnum);
302     avtpbasedepayload->seqnum = seqnum;
303   }
304   avtpbasedepayload->seqnum++;
305 
306   ptime = gst_avtp_base_depayload_tstamp_to_ptime (avtpbasedepayload, tstamp,
307       avtpbasedepayload->prev_ptime);
308 
309   subbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL,
310       sizeof (struct avtp_stream_pdu), data_len);
311   GST_BUFFER_PTS (subbuffer) = ptime;
312   GST_BUFFER_DTS (subbuffer) = ptime;
313 
314   avtpbasedepayload->prev_ptime = ptime;
315   gst_buffer_unref (buffer);
316   return gst_pad_push (avtpbasedepayload->srcpad, subbuffer);
317 
318 discard:
319   gst_buffer_unref (buffer);
320   return GST_FLOW_OK;
321 }
322