2 * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
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.
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
21 #include <gst/rtp/gstrtpbuffer.h>
23 #include "gstrtpamrenc.h"
27 * RFC 3267 - Real-Time Transport Protocol (RTP) Payload Format and File
28 * Storage Format for the Adaptive Multi-Rate (AMR) and Adaptive
29 * Multi-Rate Wideband (AMR-WB) Audio Codecs.
32 /* elementfactory information */
33 static GstElementDetails gst_rtp_amrenc_details = {
35 "Codec/Parser/Network",
36 "Encode AMR audio into RTP packets",
37 "Wim Taymans <wim@fluendo.com>"
40 /* RtpAMREnc signals and args */
47 #define DEFAULT_MTU 1024
49 #define DEFAULT_SSRC 0
59 static GstStaticPadTemplate gst_rtpamrenc_sink_template =
60 GST_STATIC_PAD_TEMPLATE ("sink",
63 GST_STATIC_CAPS ("audio/AMR, channels=(int)1, rate=(int)8000")
66 static GstStaticPadTemplate gst_rtpamrenc_src_template =
67 GST_STATIC_PAD_TEMPLATE ("src",
70 GST_STATIC_CAPS ("application/x-rtp, "
71 "octet-align = (boolean) TRUE, "
72 "crc = (boolean) FALSE, "
73 "robust-sorting = (boolean) FALSE, "
74 "interleaving = (boolean) FALSE, "
75 "channels = (int) 1, "
77 "mode-set = (int) [ 0, 7 ], "
78 "mode-change-period = (int) [ 1, MAX ], "
79 "mode-change-neighbor = (boolean) { TRUE, FALSE }, "
80 "maxptime = (int) [ 20, MAX ], " "ptime = (int) [ 20, MAX ]")
84 static void gst_rtpamrenc_class_init (GstRtpAMREncClass * klass);
85 static void gst_rtpamrenc_base_init (GstRtpAMREncClass * klass);
86 static void gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc);
88 static GstFlowReturn gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer);
90 static void gst_rtpamrenc_set_property (GObject * object, guint prop_id,
91 const GValue * value, GParamSpec * pspec);
92 static void gst_rtpamrenc_get_property (GObject * object, guint prop_id,
93 GValue * value, GParamSpec * pspec);
95 static GstElementStateReturn gst_rtpamrenc_change_state (GstElement * element);
97 static GstElementClass *parent_class = NULL;
100 gst_rtpamrenc_get_type (void)
102 static GType rtpamrenc_type = 0;
104 if (!rtpamrenc_type) {
105 static const GTypeInfo rtpamrenc_info = {
106 sizeof (GstRtpAMREncClass),
107 (GBaseInitFunc) gst_rtpamrenc_base_init,
109 (GClassInitFunc) gst_rtpamrenc_class_init,
112 sizeof (GstRtpAMREnc),
114 (GInstanceInitFunc) gst_rtpamrenc_init,
118 g_type_register_static (GST_TYPE_ELEMENT, "GstRtpAMREnc",
121 return rtpamrenc_type;
125 gst_rtpamrenc_base_init (GstRtpAMREncClass * klass)
127 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
129 gst_element_class_add_pad_template (element_class,
130 gst_static_pad_template_get (&gst_rtpamrenc_src_template));
131 gst_element_class_add_pad_template (element_class,
132 gst_static_pad_template_get (&gst_rtpamrenc_sink_template));
134 gst_element_class_set_details (element_class, &gst_rtp_amrenc_details);
138 gst_rtpamrenc_class_init (GstRtpAMREncClass * klass)
140 GObjectClass *gobject_class;
141 GstElementClass *gstelement_class;
143 gobject_class = (GObjectClass *) klass;
144 gstelement_class = (GstElementClass *) klass;
146 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
148 gobject_class->set_property = gst_rtpamrenc_set_property;
149 gobject_class->get_property = gst_rtpamrenc_get_property;
151 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
152 g_param_spec_uint ("mtu", "MTU",
153 "Maximum size of one packet",
154 28, G_MAXUINT, DEFAULT_MTU, G_PARAM_READWRITE));
155 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
156 g_param_spec_uint ("pt", "payload type",
157 "The payload type of the packets",
158 0, 0x80, DEFAULT_PT, G_PARAM_READWRITE));
159 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
160 g_param_spec_uint ("ssrc", "SSRC",
161 "The SSRC of the packets",
162 0, G_MAXUINT, DEFAULT_SSRC, G_PARAM_READWRITE));
164 gstelement_class->change_state = gst_rtpamrenc_change_state;
168 gst_rtpamrenc_init (GstRtpAMREnc * rtpamrenc)
173 gst_pad_new_from_template (gst_static_pad_template_get
174 (&gst_rtpamrenc_src_template), "src");
176 caps = gst_caps_new_simple ("application/x-rtp",
177 "octet-align", G_TYPE_BOOLEAN, TRUE,
178 "crc", G_TYPE_BOOLEAN, FALSE,
179 "robust-sorting", G_TYPE_BOOLEAN, FALSE,
180 "interleaving", G_TYPE_BOOLEAN, FALSE,
181 "channels", G_TYPE_INT, 1, "rate", G_TYPE_INT, 8000, NULL);
183 gst_pad_set_caps (rtpamrenc->srcpad, caps);
184 gst_caps_unref (caps);
185 gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->srcpad);
188 gst_pad_new_from_template (gst_static_pad_template_get
189 (&gst_rtpamrenc_sink_template), "sink");
190 gst_pad_set_chain_function (rtpamrenc->sinkpad, gst_rtpamrenc_chain);
191 gst_element_add_pad (GST_ELEMENT (rtpamrenc), rtpamrenc->sinkpad);
193 rtpamrenc->mtu = DEFAULT_MTU;
194 rtpamrenc->pt = DEFAULT_PT;
195 rtpamrenc->ssrc = DEFAULT_SSRC;
199 gst_rtpamrenc_chain (GstPad * pad, GstBuffer * buffer)
201 GstRtpAMREnc *rtpamrenc;
203 guint size, payload_len;
205 guint8 *payload, *data;
206 GstClockTime timestamp;
208 rtpamrenc = GST_RTP_AMR_ENC (gst_pad_get_parent (pad));
210 size = GST_BUFFER_SIZE (buffer);
211 timestamp = GST_BUFFER_TIMESTAMP (buffer);
213 /* FIXME, only one AMR frame per RTP packet for now,
214 * octet aligned, no interleaving, single channel, no CRC,
215 * no robust-sorting. */
217 /* we need one extra byte for the CMR, the ToC is in the input
219 payload_len = size + 1;
221 outbuf = gst_rtpbuffer_new_allocate (payload_len, 0, 0);
222 /* FIXME, assert for now */
223 g_assert (GST_BUFFER_SIZE (outbuf) < rtpamrenc->mtu);
225 gst_rtpbuffer_set_payload_type (outbuf, rtpamrenc->pt);
226 gst_rtpbuffer_set_ssrc (outbuf, rtpamrenc->ssrc);
227 gst_rtpbuffer_set_seq (outbuf, rtpamrenc->seqnum++);
228 gst_rtpbuffer_set_timestamp (outbuf, timestamp * 8000 / GST_SECOND);
231 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
234 payload = gst_rtpbuffer_get_payload (outbuf);
241 payload[0] = 0xF0; /* CMR, no specific mode requested */
243 data = GST_BUFFER_DATA (buffer);
245 /* copy data in payload */
246 memcpy (&payload[1], data, size);
254 payload[1] = payload[1] & 0x7f;
256 gst_buffer_unref (buffer);
258 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (rtpamrenc->srcpad));
260 ret = gst_pad_push (rtpamrenc->srcpad, outbuf);
262 gst_object_unref (rtpamrenc);
268 gst_rtpamrenc_set_property (GObject * object, guint prop_id,
269 const GValue * value, GParamSpec * pspec)
271 GstRtpAMREnc *rtpamrenc;
273 rtpamrenc = GST_RTP_AMR_ENC (object);
277 rtpamrenc->mtu = g_value_get_uint (value);
280 rtpamrenc->pt = g_value_get_uint (value);
283 rtpamrenc->ssrc = g_value_get_uint (value);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 gst_rtpamrenc_get_property (GObject * object, guint prop_id, GValue * value,
295 GstRtpAMREnc *rtpamrenc;
297 rtpamrenc = GST_RTP_AMR_ENC (object);
301 g_value_set_uint (value, rtpamrenc->mtu);
304 g_value_set_uint (value, rtpamrenc->pt);
307 g_value_set_uint (value, rtpamrenc->ssrc);
310 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315 static GstElementStateReturn
316 gst_rtpamrenc_change_state (GstElement * element)
318 GstRtpAMREnc *rtpamrenc;
320 GstElementStateReturn ret;
322 rtpamrenc = GST_RTP_AMR_ENC (element);
323 transition = GST_STATE_TRANSITION (element);
325 switch (transition) {
326 case GST_STATE_NULL_TO_READY:
328 case GST_STATE_READY_TO_PAUSED:
329 rtpamrenc->seqnum = 0;
335 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
337 switch (transition) {
338 case GST_STATE_READY_TO_NULL:
347 gst_rtpamrenc_plugin_init (GstPlugin * plugin)
349 return gst_element_register (plugin, "rtpamrenc",
350 GST_RANK_NONE, GST_TYPE_RTP_AMR_ENC);