Do burger's rename for rtp payloaders and depayloaders
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpmpapay.c
1 /* GStreamer
2  * Copyright (C) <2005> Wim Taymans <wim@fluendo.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 
13  */
14
15 #ifdef HAVE_CONFIG_H
16 #  include "config.h"
17 #endif
18
19 #include <string.h>
20
21 #include <gst/rtp/gstrtpbuffer.h>
22
23 #include "gstrtpmpapay.h"
24
25 /* elementfactory information */
26 static GstElementDetails gst_rtp_mpapay_details = {
27   "RTP packet parser",
28   "Codec/Payloader/Network",
29   "Payode MPEG audio as RTP packets (RFC 2038)",
30   "Wim Taymans <wim@fluendo.com>"
31 };
32
33 static GstStaticPadTemplate gst_rtp_mpa_pay_sink_template =
34 GST_STATIC_PAD_TEMPLATE ("sink",
35     GST_PAD_SINK,
36     GST_PAD_ALWAYS,
37     GST_STATIC_CAPS ("audio/mpeg")
38     );
39
40 static GstStaticPadTemplate gst_rtp_mpa_pay_src_template =
41 GST_STATIC_PAD_TEMPLATE ("src",
42     GST_PAD_SRC,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("application/x-rtp, "
45         "media = (string) \"audio\", "
46         "payload = (int) [ 96, 255 ], "
47         "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\"")
48     );
49
50 static void gst_rtp_mpa_pay_class_init (GstRtpMPAPayClass * klass);
51 static void gst_rtp_mpa_pay_base_init (GstRtpMPAPayClass * klass);
52 static void gst_rtp_mpa_pay_init (GstRtpMPAPay * rtpmpapay);
53 static void gst_rtp_mpa_pay_finalize (GObject * object);
54
55 static gboolean gst_rtp_mpa_pay_setcaps (GstBaseRTPPayload * payload,
56     GstCaps * caps);
57 static GstFlowReturn gst_rtp_mpa_pay_handle_buffer (GstBaseRTPPayload * payload,
58     GstBuffer * buffer);
59
60 static GstBaseRTPPayloadClass *parent_class = NULL;
61
62 static GType
63 gst_rtp_mpa_pay_get_type (void)
64 {
65   static GType rtpmpapay_type = 0;
66
67   if (!rtpmpapay_type) {
68     static const GTypeInfo rtpmpapay_info = {
69       sizeof (GstRtpMPAPayClass),
70       (GBaseInitFunc) gst_rtp_mpa_pay_base_init,
71       NULL,
72       (GClassInitFunc) gst_rtp_mpa_pay_class_init,
73       NULL,
74       NULL,
75       sizeof (GstRtpMPAPay),
76       0,
77       (GInstanceInitFunc) gst_rtp_mpa_pay_init,
78     };
79
80     rtpmpapay_type =
81         g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMPAPay",
82         &rtpmpapay_info, 0);
83   }
84   return rtpmpapay_type;
85 }
86
87 static void
88 gst_rtp_mpa_pay_base_init (GstRtpMPAPayClass * klass)
89 {
90   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
91
92   gst_element_class_add_pad_template (element_class,
93       gst_static_pad_template_get (&gst_rtp_mpa_pay_src_template));
94   gst_element_class_add_pad_template (element_class,
95       gst_static_pad_template_get (&gst_rtp_mpa_pay_sink_template));
96
97   gst_element_class_set_details (element_class, &gst_rtp_mpapay_details);
98 }
99
100 static void
101 gst_rtp_mpa_pay_class_init (GstRtpMPAPayClass * klass)
102 {
103   GObjectClass *gobject_class;
104   GstElementClass *gstelement_class;
105   GstBaseRTPPayloadClass *gstbasertppayload_class;
106
107   gobject_class = (GObjectClass *) klass;
108   gstelement_class = (GstElementClass *) klass;
109   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
110
111   parent_class = g_type_class_ref (GST_TYPE_BASE_RTP_PAYLOAD);
112
113   gobject_class->finalize = gst_rtp_mpa_pay_finalize;
114
115   gstbasertppayload_class->set_caps = gst_rtp_mpa_pay_setcaps;
116   gstbasertppayload_class->handle_buffer = gst_rtp_mpa_pay_handle_buffer;
117 }
118
119 static void
120 gst_rtp_mpa_pay_init (GstRtpMPAPay * rtpmpapay)
121 {
122   rtpmpapay->adapter = gst_adapter_new ();
123 }
124
125 static void
126 gst_rtp_mpa_pay_finalize (GObject * object)
127 {
128   GstRtpMPAPay *rtpmpapay;
129
130   rtpmpapay = GST_RTP_MPA_PAY (object);
131
132   g_object_unref (rtpmpapay->adapter);
133   rtpmpapay->adapter = NULL;
134
135   G_OBJECT_CLASS (parent_class)->finalize (object);
136 }
137
138 static gboolean
139 gst_rtp_mpa_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
140 {
141   gst_basertppayload_set_options (payload, "audio", TRUE, "MPA", 90000);
142   gst_basertppayload_set_outcaps (payload, NULL);
143
144   return TRUE;
145 }
146
147 static GstFlowReturn
148 gst_rtp_mpa_pay_flush (GstRtpMPAPay * rtpmpapay)
149 {
150   guint avail;
151   GstBuffer *outbuf;
152   GstFlowReturn ret;
153   guint16 frag_offset;
154
155   /* the data available in the adapter is either smaller
156    * than the MTU or bigger. In the case it is smaller, the complete
157    * adapter contents can be put in one packet. In the case the
158    * adapter has more than one MTU, we need to split the MPA data
159    * over multiple packets. The frag_offset in each packet header
160    * needs to be updated with the position in the MPA frame. */
161   avail = gst_adapter_available (rtpmpapay->adapter);
162
163   ret = GST_FLOW_OK;
164
165   frag_offset = 0;
166   while (avail > 0) {
167     guint towrite;
168     guint8 *payload;
169     guint8 *data;
170     guint payload_len;
171     guint packet_len;
172
173     /* this will be the total lenght of the packet */
174     packet_len = gst_rtp_buffer_calc_packet_len (4 + avail, 0, 0);
175
176     /* fill one MTU or all available bytes */
177     towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmpapay));
178
179     /* this is the payload length */
180     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
181
182     /* create buffer to hold the payload */
183     outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
184
185     payload_len -= 4;
186
187     gst_rtp_buffer_set_payload_type (outbuf, GST_RTP_PAYLOAD_MPA);
188
189     /*
190      *  0                   1                   2                   3
191      *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
192      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
193      * |             MBZ               |          Frag_offset          |
194      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 
195      */
196     payload = gst_rtp_buffer_get_payload (outbuf);
197     payload[0] = 0;
198     payload[1] = 0;
199     payload[2] = frag_offset >> 8;
200     payload[3] = frag_offset & 0xff;
201
202     data = (guint8 *) gst_adapter_peek (rtpmpapay->adapter, payload_len);
203     memcpy (&payload[4], data, payload_len);
204     gst_adapter_flush (rtpmpapay->adapter, payload_len);
205
206     avail -= payload_len;
207     frag_offset += payload_len;
208
209     if (avail == 0)
210       gst_rtp_buffer_set_marker (outbuf, TRUE);
211
212     GST_BUFFER_TIMESTAMP (outbuf) = rtpmpapay->first_ts;
213     GST_BUFFER_DURATION (outbuf) = rtpmpapay->duration;
214
215     ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmpapay), outbuf);
216   }
217
218   return ret;
219 }
220
221 static GstFlowReturn
222 gst_rtp_mpa_pay_handle_buffer (GstBaseRTPPayload * basepayload,
223     GstBuffer * buffer)
224 {
225   GstRtpMPAPay *rtpmpapay;
226   GstFlowReturn ret;
227   guint size, avail;
228   guint packet_len;
229   GstClockTime duration;
230
231   rtpmpapay = GST_RTP_MPA_PAY (basepayload);
232
233   size = GST_BUFFER_SIZE (buffer);
234   duration = GST_BUFFER_DURATION (buffer);
235
236   avail = gst_adapter_available (rtpmpapay->adapter);
237   if (avail == 0) {
238     rtpmpapay->first_ts = GST_BUFFER_TIMESTAMP (buffer);
239     rtpmpapay->duration = 0;
240   }
241
242   /* get packet length of previous data and this new data, 
243    * payload length includes a 4 byte header */
244   packet_len = gst_rtp_buffer_calc_packet_len (4 + avail + size, 0, 0);
245
246   /* if this buffer is going to overflow the packet, flush what we
247    * have. */
248   if (gst_basertppayload_is_filled (basepayload,
249           packet_len, rtpmpapay->duration + duration)) {
250     ret = gst_rtp_mpa_pay_flush (rtpmpapay);
251     rtpmpapay->first_ts = GST_BUFFER_TIMESTAMP (buffer);
252     rtpmpapay->duration = 0;
253   } else {
254     ret = GST_FLOW_OK;
255   }
256
257   gst_adapter_push (rtpmpapay->adapter, buffer);
258   rtpmpapay->duration += duration;
259
260   return ret;
261 }
262
263 gboolean
264 gst_rtp_mpa_pay_plugin_init (GstPlugin * plugin)
265 {
266   return gst_element_register (plugin, "rtpmpapay",
267       GST_RANK_NONE, GST_TYPE_RTP_MPA_PAY);
268 }