rtpL16(de)pay: fix raw audio format in template caps
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpL16pay.c
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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <string.h>
25
26 #include <gst/audio/audio.h>
27 #include <gst/rtp/gstrtpbuffer.h>
28
29 #include "gstrtpL16pay.h"
30 #include "gstrtpchannels.h"
31
32 GST_DEBUG_CATEGORY_STATIC (rtpL16pay_debug);
33 #define GST_CAT_DEFAULT (rtpL16pay_debug)
34
35 static GstStaticPadTemplate gst_rtp_L16_pay_sink_template =
36 GST_STATIC_PAD_TEMPLATE ("sink",
37     GST_PAD_SINK,
38     GST_PAD_ALWAYS,
39     GST_STATIC_CAPS ("audio/x-raw, "
40         "format = (string) S16BE, "
41         "layout = (string) interleaved, "
42         "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]")
43     );
44
45 static GstStaticPadTemplate gst_rtp_L16_pay_src_template =
46     GST_STATIC_PAD_TEMPLATE ("src",
47     GST_PAD_SRC,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("application/x-rtp, "
50         "media = (string) \"audio\", "
51         "payload = (int) [ 96, 127 ], "
52         "clock-rate = (int) [ 1, MAX ], "
53         "encoding-name = (string) \"L16\", "
54         "channels = (int) [ 1, MAX ];"
55         "application/x-rtp, "
56         "media = (string) \"audio\", "
57         "encoding-name = (string) \"L16\", "
58         "payload = (int) " GST_RTP_PAYLOAD_L16_STEREO_STRING ", "
59         "clock-rate = (int) 44100;"
60         "application/x-rtp, "
61         "media = (string) \"audio\", "
62         "encoding-name = (string) \"L16\", "
63         "payload = (int) " GST_RTP_PAYLOAD_L16_MONO_STRING ", "
64         "clock-rate = (int) 44100")
65     );
66
67 static gboolean gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload,
68     GstCaps * caps);
69 static GstCaps *gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload,
70     GstPad * pad, GstCaps * filter);
71 static GstFlowReturn
72 gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
73     GstBuffer * buffer);
74
75 #define gst_rtp_L16_pay_parent_class parent_class
76 G_DEFINE_TYPE (GstRtpL16Pay, gst_rtp_L16_pay, GST_TYPE_RTP_BASE_AUDIO_PAYLOAD);
77
78 static void
79 gst_rtp_L16_pay_class_init (GstRtpL16PayClass * klass)
80 {
81   GstElementClass *gstelement_class;
82   GstRTPBasePayloadClass *gstrtpbasepayload_class;
83
84   gstelement_class = (GstElementClass *) klass;
85   gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
86
87   gstrtpbasepayload_class->set_caps = gst_rtp_L16_pay_setcaps;
88   gstrtpbasepayload_class->get_caps = gst_rtp_L16_pay_getcaps;
89   gstrtpbasepayload_class->handle_buffer = gst_rtp_L16_pay_handle_buffer;
90
91   gst_element_class_add_pad_template (gstelement_class,
92       gst_static_pad_template_get (&gst_rtp_L16_pay_src_template));
93   gst_element_class_add_pad_template (gstelement_class,
94       gst_static_pad_template_get (&gst_rtp_L16_pay_sink_template));
95
96   gst_element_class_set_details_simple (gstelement_class, "RTP audio payloader",
97       "Codec/Payloader/Network/RTP",
98       "Payload-encode Raw audio into RTP packets (RFC 3551)",
99       "Wim Taymans <wim.taymans@gmail.com>");
100
101   GST_DEBUG_CATEGORY_INIT (rtpL16pay_debug, "rtpL16pay", 0,
102       "L16 RTP Payloader");
103 }
104
105 static void
106 gst_rtp_L16_pay_init (GstRtpL16Pay * rtpL16pay)
107 {
108   GstRTPBaseAudioPayload *rtpbaseaudiopayload;
109
110   rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (rtpL16pay);
111
112   /* tell rtpbaseaudiopayload that this is a sample based codec */
113   gst_rtp_base_audio_payload_set_sample_based (rtpbaseaudiopayload);
114 }
115
116 static gboolean
117 gst_rtp_L16_pay_setcaps (GstRTPBasePayload * basepayload, GstCaps * caps)
118 {
119   GstRtpL16Pay *rtpL16pay;
120   gboolean res;
121   gchar *params;
122   GstAudioInfo *info;
123   const GstRTPChannelOrder *order;
124   GstRTPBaseAudioPayload *rtpbaseaudiopayload;
125
126   rtpbaseaudiopayload = GST_RTP_BASE_AUDIO_PAYLOAD (basepayload);
127   rtpL16pay = GST_RTP_L16_PAY (basepayload);
128
129   info = &rtpL16pay->info;
130   gst_audio_info_init (info);
131   if (!gst_audio_info_from_caps (info, caps))
132     goto invalid_caps;
133
134   order = gst_rtp_channels_get_by_pos (info->channels, info->position);
135   rtpL16pay->order = order;
136
137   gst_rtp_base_payload_set_options (basepayload, "audio", TRUE, "L16",
138       info->rate);
139   params = g_strdup_printf ("%d", info->channels);
140
141   if (!order && info->channels > 2) {
142     GST_ELEMENT_WARNING (rtpL16pay, STREAM, DECODE,
143         (NULL), ("Unknown channel order for %d channels", info->channels));
144   }
145
146   if (order && order->name) {
147     res = gst_rtp_base_payload_set_outcaps (basepayload,
148         "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
149         info->channels, "channel-order", G_TYPE_STRING, order->name, NULL);
150   } else {
151     res = gst_rtp_base_payload_set_outcaps (basepayload,
152         "encoding-params", G_TYPE_STRING, params, "channels", G_TYPE_INT,
153         info->channels, NULL);
154   }
155
156   g_free (params);
157
158   /* octet-per-sample is 2 * channels for L16 */
159   gst_rtp_base_audio_payload_set_sample_options (rtpbaseaudiopayload,
160       2 * info->channels);
161
162   return res;
163
164   /* ERRORS */
165 invalid_caps:
166   {
167     GST_DEBUG_OBJECT (rtpL16pay, "invalid caps");
168     return FALSE;
169   }
170 }
171
172 static GstCaps *
173 gst_rtp_L16_pay_getcaps (GstRTPBasePayload * rtppayload, GstPad * pad,
174     GstCaps * filter)
175 {
176   GstCaps *otherpadcaps;
177   GstCaps *caps;
178
179   otherpadcaps = gst_pad_get_allowed_caps (rtppayload->srcpad);
180   caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
181
182   if (otherpadcaps) {
183     if (!gst_caps_is_empty (otherpadcaps)) {
184       GstStructure *structure;
185       gint channels;
186       gint pt;
187       gint rate;
188
189       structure = gst_caps_get_structure (otherpadcaps, 0);
190
191       if (gst_structure_get_int (structure, "channels", &channels)) {
192         gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
193       } else if (gst_structure_get_int (structure, "payload", &pt)) {
194         if (pt == 10)
195           gst_caps_set_simple (caps, "channels", G_TYPE_INT, 2, NULL);
196         else if (pt == 11)
197           gst_caps_set_simple (caps, "channels", G_TYPE_INT, 1, NULL);
198       }
199
200       if (gst_structure_get_int (structure, "clock-rate", &rate)) {
201         gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
202       } else if (gst_structure_get_int (structure, "payload", &pt)) {
203         if (pt == 10 || pt == 11)
204           gst_caps_set_simple (caps, "rate", G_TYPE_INT, 44100, NULL);
205       }
206
207     }
208     gst_caps_unref (otherpadcaps);
209   }
210
211   if (filter) {
212     GstCaps *tcaps = caps;
213
214     caps = gst_caps_intersect_full (filter, tcaps, GST_CAPS_INTERSECT_FIRST);
215     gst_caps_unref (tcaps);
216   }
217
218   return caps;
219 }
220
221 static GstFlowReturn
222 gst_rtp_L16_pay_handle_buffer (GstRTPBasePayload * basepayload,
223     GstBuffer * buffer)
224 {
225   GstRtpL16Pay *rtpL16pay;
226
227   rtpL16pay = GST_RTP_L16_PAY (basepayload);
228   buffer = gst_buffer_make_writable (buffer);
229
230   if (rtpL16pay->order &&
231       !gst_audio_buffer_reorder_channels (buffer, rtpL16pay->info.finfo->format,
232           rtpL16pay->info.channels, rtpL16pay->info.position,
233           rtpL16pay->order->pos)) {
234     return GST_FLOW_ERROR;
235   }
236
237   return GST_RTP_BASE_PAYLOAD_CLASS (parent_class)->handle_buffer (basepayload,
238       buffer);
239 }
240
241 gboolean
242 gst_rtp_L16_pay_plugin_init (GstPlugin * plugin)
243 {
244   return gst_element_register (plugin, "rtpL16pay",
245       GST_RANK_SECONDARY, GST_TYPE_RTP_L16_PAY);
246 }