Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 1 | /* GStreamer |
| 2 | * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com> |
| 3 | * |
| 4 | * This library is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU Library General Public |
| 6 | * License as published by the Free Software Foundation; either |
| 7 | * version 2 of the License, or (at your option) any later version. |
| 8 | * |
| 9 | * This library is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | * Library General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Library General Public |
| 15 | * License along with this library; if not, write to the |
Sebastian Dröge | 5f0bab0 | 2013-07-14 11:42:29 +0200 | [diff] [blame] | 16 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
| 17 | * Boston, MA 02110-1301, USA. |
| 18 | */ |
| 19 | |
| 20 | /** |
| 21 | * SECTION:element-rtpL16depay |
| 22 | * @see_also: rtpL16pay |
| 23 | * |
| 24 | * Extract raw audio from RTP packets according to RFC 3551. |
| 25 | * For detailed information see: http://www.rfc-editor.org/rfc/rfc3551.txt |
| 26 | * |
| 27 | * <refsect2> |
| 28 | * <title>Example pipeline</title> |
| 29 | * |[ |
Sebastian Dröge | 010e029 | 2015-05-13 13:24:03 +0300 | [diff] [blame] | 30 | * gst-launch-1.0 udpsrc caps='application/x-rtp, media=(string)audio, clock-rate=(int)44100, encoding-name=(string)L16, encoding-params=(string)1, channels=(int)1, payload=(int)96' ! rtpL16depay ! pulsesink |
Sebastian Dröge | 5f0bab0 | 2013-07-14 11:42:29 +0200 | [diff] [blame] | 31 | * ]| This example pipeline will depayload an RTP raw audio stream. Refer to |
| 32 | * the rtpL16pay example to create the RTP stream. |
| 33 | * </refsect2> |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 34 | */ |
| 35 | |
| 36 | #ifdef HAVE_CONFIG_H |
| 37 | #include "config.h" |
| 38 | #endif |
| 39 | |
| 40 | #include <string.h> |
| 41 | #include <stdlib.h> |
| 42 | |
| 43 | #include <gst/audio/audio.h> |
| 44 | |
| 45 | #include "gstrtpL16depay.h" |
| 46 | #include "gstrtpchannels.h" |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 47 | #include "gstrtputils.h" |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 48 | |
| 49 | GST_DEBUG_CATEGORY_STATIC (rtpL16depay_debug); |
| 50 | #define GST_CAT_DEFAULT (rtpL16depay_debug) |
| 51 | |
| 52 | static GstStaticPadTemplate gst_rtp_L16_depay_src_template = |
| 53 | GST_STATIC_PAD_TEMPLATE ("src", |
| 54 | GST_PAD_SRC, |
| 55 | GST_PAD_ALWAYS, |
| 56 | GST_STATIC_CAPS ("audio/x-raw, " |
| 57 | "format = (string) S16BE, " |
| 58 | "layout = (string) interleaved, " |
| 59 | "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]") |
| 60 | ); |
| 61 | |
| 62 | static GstStaticPadTemplate gst_rtp_L16_depay_sink_template = |
| 63 | GST_STATIC_PAD_TEMPLATE ("sink", |
| 64 | GST_PAD_SINK, |
| 65 | GST_PAD_ALWAYS, |
| 66 | GST_STATIC_CAPS ("application/x-rtp, " |
Sebastian Dröge | 5f0bab0 | 2013-07-14 11:42:29 +0200 | [diff] [blame] | 67 | "media = (string) \"audio\", " "clock-rate = (int) [ 1, MAX ], " |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 68 | /* "channels = (int) [1, MAX]" */ |
| 69 | /* "emphasis = (string) ANY" */ |
| 70 | /* "channel-order = (string) ANY" */ |
| 71 | "encoding-name = (string) \"L16\";" |
| 72 | "application/x-rtp, " |
| 73 | "media = (string) \"audio\", " |
| 74 | "payload = (int) { " GST_RTP_PAYLOAD_L16_STEREO_STRING ", " |
| 75 | GST_RTP_PAYLOAD_L16_MONO_STRING " }," "clock-rate = (int) [ 1, MAX ]" |
| 76 | /* "channels = (int) [1, MAX]" */ |
| 77 | /* "emphasis = (string) ANY" */ |
| 78 | /* "channel-order = (string) ANY" */ |
| 79 | ) |
| 80 | ); |
| 81 | |
| 82 | #define gst_rtp_L16_depay_parent_class parent_class |
| 83 | G_DEFINE_TYPE (GstRtpL16Depay, gst_rtp_L16_depay, GST_TYPE_RTP_BASE_DEPAYLOAD); |
| 84 | |
| 85 | static gboolean gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, |
| 86 | GstCaps * caps); |
| 87 | static GstBuffer *gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 88 | GstRTPBuffer * rtp); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 89 | |
| 90 | static void |
| 91 | gst_rtp_L16_depay_class_init (GstRtpL16DepayClass * klass) |
| 92 | { |
| 93 | GstElementClass *gstelement_class; |
| 94 | GstRTPBaseDepayloadClass *gstrtpbasedepayload_class; |
| 95 | |
| 96 | gstelement_class = (GstElementClass *) klass; |
| 97 | gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass; |
| 98 | |
| 99 | gstrtpbasedepayload_class->set_caps = gst_rtp_L16_depay_setcaps; |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 100 | gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_L16_depay_process; |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 101 | |
Sebastian Dröge | 3a50aa7 | 2016-07-06 12:38:23 +0300 | [diff] [blame] | 102 | gst_element_class_add_static_pad_template (gstelement_class, |
| 103 | &gst_rtp_L16_depay_src_template); |
| 104 | gst_element_class_add_static_pad_template (gstelement_class, |
| 105 | &gst_rtp_L16_depay_sink_template); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 106 | |
| 107 | gst_element_class_set_static_metadata (gstelement_class, |
| 108 | "RTP audio depayloader", "Codec/Depayloader/Network/RTP", |
| 109 | "Extracts raw audio from RTP packets", |
| 110 | "Zeeshan Ali <zak147@yahoo.com>," "Wim Taymans <wim.taymans@gmail.com>"); |
| 111 | |
| 112 | GST_DEBUG_CATEGORY_INIT (rtpL16depay_debug, "rtpL16depay", 0, |
| 113 | "Raw Audio RTP Depayloader"); |
| 114 | } |
| 115 | |
| 116 | static void |
| 117 | gst_rtp_L16_depay_init (GstRtpL16Depay * rtpL16depay) |
| 118 | { |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 119 | } |
| 120 | |
| 121 | static gint |
| 122 | gst_rtp_L16_depay_parse_int (GstStructure * structure, const gchar * field, |
| 123 | gint def) |
| 124 | { |
| 125 | const gchar *str; |
| 126 | gint res; |
| 127 | |
| 128 | if ((str = gst_structure_get_string (structure, field))) |
| 129 | return atoi (str); |
| 130 | |
| 131 | if (gst_structure_get_int (structure, field, &res)) |
| 132 | return res; |
| 133 | |
| 134 | return def; |
| 135 | } |
| 136 | |
| 137 | static gboolean |
| 138 | gst_rtp_L16_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps) |
| 139 | { |
| 140 | GstStructure *structure; |
| 141 | GstRtpL16Depay *rtpL16depay; |
| 142 | gint clock_rate, payload; |
| 143 | gint channels; |
| 144 | GstCaps *srccaps; |
| 145 | gboolean res; |
| 146 | const gchar *channel_order; |
| 147 | const GstRTPChannelOrder *order; |
| 148 | GstAudioInfo *info; |
| 149 | |
| 150 | rtpL16depay = GST_RTP_L16_DEPAY (depayload); |
| 151 | |
| 152 | structure = gst_caps_get_structure (caps, 0); |
| 153 | |
| 154 | payload = 96; |
| 155 | gst_structure_get_int (structure, "payload", &payload); |
| 156 | switch (payload) { |
| 157 | case GST_RTP_PAYLOAD_L16_STEREO: |
| 158 | channels = 2; |
| 159 | clock_rate = 44100; |
| 160 | break; |
| 161 | case GST_RTP_PAYLOAD_L16_MONO: |
| 162 | channels = 1; |
| 163 | clock_rate = 44100; |
| 164 | break; |
| 165 | default: |
| 166 | /* no fixed mapping, we need clock-rate */ |
| 167 | channels = 0; |
| 168 | clock_rate = 0; |
| 169 | break; |
| 170 | } |
| 171 | |
| 172 | /* caps can overwrite defaults */ |
| 173 | clock_rate = |
| 174 | gst_rtp_L16_depay_parse_int (structure, "clock-rate", clock_rate); |
| 175 | if (clock_rate == 0) |
| 176 | goto no_clockrate; |
| 177 | |
| 178 | channels = |
| 179 | gst_rtp_L16_depay_parse_int (structure, "encoding-params", channels); |
| 180 | if (channels == 0) { |
| 181 | channels = gst_rtp_L16_depay_parse_int (structure, "channels", channels); |
| 182 | if (channels == 0) { |
| 183 | /* channels defaults to 1 otherwise */ |
| 184 | channels = 1; |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | depayload->clock_rate = clock_rate; |
| 189 | |
| 190 | info = &rtpL16depay->info; |
| 191 | gst_audio_info_init (info); |
| 192 | info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_S16BE); |
| 193 | info->rate = clock_rate; |
| 194 | info->channels = channels; |
| 195 | info->bpf = (info->finfo->width / 8) * channels; |
| 196 | |
| 197 | /* add channel positions */ |
| 198 | channel_order = gst_structure_get_string (structure, "channel-order"); |
| 199 | |
| 200 | order = gst_rtp_channels_get_by_order (channels, channel_order); |
| 201 | rtpL16depay->order = order; |
| 202 | if (order) { |
| 203 | memcpy (info->position, order->pos, |
| 204 | sizeof (GstAudioChannelPosition) * channels); |
| 205 | gst_audio_channel_positions_to_valid_order (info->position, info->channels); |
| 206 | } else { |
| 207 | GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, |
| 208 | (NULL), ("Unknown channel order '%s' for %d channels", |
| 209 | GST_STR_NULL (channel_order), channels)); |
| 210 | /* create default NONE layout */ |
| 211 | gst_rtp_channels_create_default (channels, info->position); |
| 212 | } |
| 213 | |
| 214 | srccaps = gst_audio_info_to_caps (info); |
| 215 | res = gst_pad_set_caps (depayload->srcpad, srccaps); |
| 216 | gst_caps_unref (srccaps); |
| 217 | |
| 218 | return res; |
| 219 | |
| 220 | /* ERRORS */ |
| 221 | no_clockrate: |
| 222 | { |
| 223 | GST_ERROR_OBJECT (depayload, "no clock-rate specified"); |
| 224 | return FALSE; |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | static GstBuffer * |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 229 | gst_rtp_L16_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp) |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 230 | { |
| 231 | GstRtpL16Depay *rtpL16depay; |
| 232 | GstBuffer *outbuf; |
| 233 | gint payload_len; |
| 234 | gboolean marker; |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 235 | |
| 236 | rtpL16depay = GST_RTP_L16_DEPAY (depayload); |
| 237 | |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 238 | payload_len = gst_rtp_buffer_get_payload_len (rtp); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 239 | |
| 240 | if (payload_len <= 0) |
| 241 | goto empty_packet; |
| 242 | |
| 243 | GST_DEBUG_OBJECT (rtpL16depay, "got payload of %d bytes", payload_len); |
| 244 | |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 245 | outbuf = gst_rtp_buffer_get_payload_buffer (rtp); |
| 246 | marker = gst_rtp_buffer_get_marker (rtp); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 247 | |
| 248 | if (marker) { |
Sebastian Dröge | 5f0bab0 | 2013-07-14 11:42:29 +0200 | [diff] [blame] | 249 | /* mark talk spurt with RESYNC */ |
| 250 | GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_RESYNC); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 251 | } |
| 252 | |
| 253 | outbuf = gst_buffer_make_writable (outbuf); |
| 254 | if (rtpL16depay->order && |
| 255 | !gst_audio_buffer_reorder_channels (outbuf, |
| 256 | rtpL16depay->info.finfo->format, rtpL16depay->info.channels, |
| 257 | rtpL16depay->info.position, rtpL16depay->order->pos)) { |
| 258 | goto reorder_failed; |
| 259 | } |
| 260 | |
Sebastian Dröge | b04f972 | 2015-08-19 13:19:08 +0300 | [diff] [blame] | 261 | gst_rtp_drop_meta (GST_ELEMENT_CAST (rtpL16depay), outbuf, |
| 262 | g_quark_from_static_string (GST_META_TAG_AUDIO_STR)); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 263 | |
| 264 | return outbuf; |
| 265 | |
| 266 | /* ERRORS */ |
| 267 | empty_packet: |
| 268 | { |
| 269 | GST_ELEMENT_WARNING (rtpL16depay, STREAM, DECODE, |
| 270 | ("Empty Payload."), (NULL)); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 271 | return NULL; |
| 272 | } |
| 273 | reorder_failed: |
| 274 | { |
| 275 | GST_ELEMENT_ERROR (rtpL16depay, STREAM, DECODE, |
| 276 | ("Channel reordering failed."), (NULL)); |
Olivier Naudan | 988c6f0 | 2012-04-16 07:16:25 -0400 | [diff] [blame] | 277 | return NULL; |
| 278 | } |
| 279 | } |
| 280 | |
| 281 | gboolean |
| 282 | gst_rtp_L16_depay_plugin_init (GstPlugin * plugin) |
| 283 | { |
| 284 | return gst_element_register (plugin, "rtpL16depay", |
| 285 | GST_RANK_SECONDARY, GST_TYPE_RTP_L16_DEPAY); |
| 286 | } |