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