tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / gst / rtp / gstrtpqdmdepay.c
1 /* GStreamer
2  * Copyright (C) <2009> Edward Hervey <bilboed@bilboed.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/rtp/gstrtpbuffer.h>
27 #include "gstrtpqdmdepay.h"
28
29 GST_DEBUG_CATEGORY (rtpqdm2depay_debug);
30 #define GST_CAT_DEFAULT rtpqdm2depay_debug
31
32 static GstStaticPadTemplate gst_rtp_qdm2_depay_src_template =
33 GST_STATIC_PAD_TEMPLATE ("src",
34     GST_PAD_SRC,
35     GST_PAD_ALWAYS,
36     GST_STATIC_CAPS ("audio/x-qdm2")
37     );
38
39 static GstStaticPadTemplate gst_rtp_qdm2_depay_sink_template =
40 GST_STATIC_PAD_TEMPLATE ("sink",
41     GST_PAD_SINK,
42     GST_PAD_ALWAYS,
43     GST_STATIC_CAPS ("application/x-rtp, "
44         "media = (string) \"audio\", "
45         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
46         "encoding-name = (string)\"X-QDM\"")
47     );
48
49 GST_BOILERPLATE (GstRtpQDM2Depay, gst_rtp_qdm2_depay, GstBaseRTPDepayload,
50     GST_TYPE_BASE_RTP_DEPAYLOAD);
51
52 static const guint8 headheader[20] = {
53   0x0, 0x0, 0x0, 0xc, 0x66, 0x72, 0x6d, 0x61,
54   0x51, 0x44, 0x4d, 0x32, 0x0, 0x0, 0x0, 0x24,
55   0x51, 0x44, 0x43, 0x41
56 };
57
58 static void gst_rtp_qdm2_depay_finalize (GObject * object);
59
60 static GstStateChangeReturn gst_rtp_qdm2_depay_change_state (GstElement *
61     element, GstStateChange transition);
62
63 static GstBuffer *gst_rtp_qdm2_depay_process (GstBaseRTPDepayload * depayload,
64     GstBuffer * buf);
65 gboolean gst_rtp_qdm2_depay_setcaps (GstBaseRTPDepayload * filter,
66     GstCaps * caps);
67
68 static void
69 gst_rtp_qdm2_depay_base_init (gpointer klass)
70 {
71   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
72
73   gst_element_class_add_static_pad_template (element_class,
74       &gst_rtp_qdm2_depay_src_template);
75   gst_element_class_add_static_pad_template (element_class,
76       &gst_rtp_qdm2_depay_sink_template);
77
78
79   gst_element_class_set_details_simple (element_class, "RTP QDM2 depayloader",
80       "Codec/Depayloader/Network/RTP",
81       "Extracts QDM2 audio from RTP packets (no RFC)",
82       "Edward Hervey <bilboed@bilboed.com>");
83 }
84
85 static void
86 gst_rtp_qdm2_depay_class_init (GstRtpQDM2DepayClass * klass)
87 {
88   GObjectClass *gobject_class;
89   GstElementClass *gstelement_class;
90   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
91
92   gobject_class = (GObjectClass *) klass;
93   gstelement_class = (GstElementClass *) klass;
94   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
95
96   gstbasertpdepayload_class->process = gst_rtp_qdm2_depay_process;
97   gstbasertpdepayload_class->set_caps = gst_rtp_qdm2_depay_setcaps;
98
99   gobject_class->finalize = gst_rtp_qdm2_depay_finalize;
100
101   gstelement_class->change_state = gst_rtp_qdm2_depay_change_state;
102 }
103
104 static void
105 gst_rtp_qdm2_depay_init (GstRtpQDM2Depay * rtpqdm2depay,
106     GstRtpQDM2DepayClass * klass)
107 {
108   rtpqdm2depay->adapter = gst_adapter_new ();
109 }
110
111 static void
112 gst_rtp_qdm2_depay_finalize (GObject * object)
113 {
114   GstRtpQDM2Depay *rtpqdm2depay;
115
116   rtpqdm2depay = GST_RTP_QDM2_DEPAY (object);
117
118   g_object_unref (rtpqdm2depay->adapter);
119   rtpqdm2depay->adapter = NULL;
120
121   G_OBJECT_CLASS (parent_class)->finalize (object);
122 }
123
124 // only on the sink
125 gboolean
126 gst_rtp_qdm2_depay_setcaps (GstBaseRTPDepayload * filter, GstCaps * caps)
127 {
128   GstStructure *structure = gst_caps_get_structure (caps, 0);
129   gint clock_rate;
130
131   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
132     clock_rate = 44100;         // default
133   filter->clock_rate = clock_rate;
134
135   /* will set caps later */
136
137   return TRUE;
138 }
139
140 static void
141 flush_data (GstRtpQDM2Depay * depay)
142 {
143   guint i;
144   guint avail;
145
146   if ((avail = gst_adapter_available (depay->adapter)))
147     gst_adapter_flush (depay->adapter, avail);
148
149   GST_DEBUG ("Flushing %d packets", depay->nbpackets);
150
151   for (i = 0; depay->packets[i]; i++) {
152     QDM2Packet *pack = depay->packets[i];
153     guint32 crc = 0;
154     int i = 0;
155     GstBuffer *buf;
156     guint8 *data;
157
158     /* CRC is the sum of everything (including first bytes) */
159
160     data = pack->data;
161
162     if (G_UNLIKELY (data == NULL))
163       continue;
164
165     /* If the packet size is bigger than 0xff, we need 2 bytes to store the size */
166     if (depay->packetsize > 0xff) {
167       /* Expanded size 0x02 | 0x80 */
168       data[0] = 0x82;
169       GST_WRITE_UINT16_BE (data + 1, depay->packetsize - 3);
170     } else {
171       data[0] = 0x2;
172       data[1] = depay->packetsize - 2;
173     }
174
175     /* Calculate CRC */
176     for (; i < depay->packetsize; i++)
177       crc += data[i];
178
179     GST_DEBUG ("CRC is 0x%x", crc);
180
181     /* Write CRC */
182     if (depay->packetsize > 0xff)
183       GST_WRITE_UINT16_BE (data + 3, crc);
184     else
185       GST_WRITE_UINT16_BE (data + 2, crc);
186
187     GST_MEMDUMP ("Extracted packet", data, depay->packetsize);
188
189     buf = gst_buffer_new ();
190     GST_BUFFER_DATA (buf) = data;
191     GST_BUFFER_MALLOCDATA (buf) = data;
192     GST_BUFFER_SIZE (buf) = depay->packetsize;
193
194     gst_adapter_push (depay->adapter, buf);
195
196     if (pack->data) {
197       pack->data = NULL;
198     }
199   }
200 }
201
202 static void
203 add_packet (GstRtpQDM2Depay * depay, guint32 pid, guint32 len, guint8 * data)
204 {
205   QDM2Packet *packet;
206
207   if (G_UNLIKELY (!depay->configured))
208     return;
209
210   GST_DEBUG ("pid:%d, len:%d, data:%p", pid, len, data);
211
212   if (G_UNLIKELY (depay->packets[pid] == NULL)) {
213     depay->packets[pid] = g_malloc0 (sizeof (QDM2Packet));
214     depay->nbpackets = MAX (depay->nbpackets, pid + 1);
215   }
216   packet = depay->packets[pid];
217
218   GST_DEBUG ("packet:%p", packet);
219   GST_DEBUG ("packet->data:%p", packet->data);
220
221   if (G_UNLIKELY (packet->data == NULL)) {
222     packet->data = g_malloc0 (depay->packetsize);
223     /* We leave space for the header/crc */
224     if (depay->packetsize > 0xff)
225       packet->offs = 5;
226     else
227       packet->offs = 4;
228   }
229
230   /* Finally copy the data over */
231   memcpy (packet->data + packet->offs, data, len);
232   packet->offs += len;
233 }
234
235 static GstBuffer *
236 gst_rtp_qdm2_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
237 {
238   GstRtpQDM2Depay *rtpqdm2depay;
239   GstBuffer *outbuf;
240   guint16 seq;
241
242   rtpqdm2depay = GST_RTP_QDM2_DEPAY (depayload);
243
244   {
245     gint payload_len;
246     guint8 *payload;
247     guint avail;
248     guint pos = 0;
249
250     payload_len = gst_rtp_buffer_get_payload_len (buf);
251     if (payload_len < 3)
252       goto bad_packet;
253
254     payload = gst_rtp_buffer_get_payload (buf);
255     seq = gst_rtp_buffer_get_seq (buf);
256     if (G_UNLIKELY (seq != rtpqdm2depay->nextseq)) {
257       GST_DEBUG ("GAP in sequence number, Resetting data !");
258       /* Flush previous data */
259       flush_data (rtpqdm2depay);
260       /* And store new timestamp */
261       rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
262       rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
263       /* And that previous data will be pushed at the bottom */
264     }
265     rtpqdm2depay->nextseq = seq + 1;
266
267     GST_DEBUG ("Payload size %d 0x%x sequence:%d", payload_len, payload_len,
268         seq);
269
270     GST_MEMDUMP ("Incoming payload", payload, payload_len);
271
272     while (pos < payload_len) {
273       switch (payload[pos]) {
274         case 0x80:{
275           GST_DEBUG ("Unrecognized 0x80 marker, skipping 12 bytes");
276           pos += 12;
277         }
278           break;
279         case 0xff:
280           /* HEADERS */
281           GST_DEBUG ("Headers");
282           /* Store the incoming timestamp */
283           rtpqdm2depay->ptimestamp = rtpqdm2depay->timestamp;
284           rtpqdm2depay->timestamp = GST_BUFFER_TIMESTAMP (buf);
285           /* flush the internal data if needed */
286           flush_data (rtpqdm2depay);
287           if (G_UNLIKELY (!rtpqdm2depay->configured)) {
288             guint8 *ourdata;
289             GstBuffer *codecdata;
290             GstCaps *caps;
291
292             /* First bytes are unknown */
293             GST_MEMDUMP ("Header", payload + pos, 32);
294             ourdata = payload + pos + 10;
295             pos += 10;
296             rtpqdm2depay->channs = GST_READ_UINT32_BE (payload + pos + 4);
297             rtpqdm2depay->samplerate = GST_READ_UINT32_BE (payload + pos + 8);
298             rtpqdm2depay->bitrate = GST_READ_UINT32_BE (payload + pos + 12);
299             rtpqdm2depay->blocksize = GST_READ_UINT32_BE (payload + pos + 16);
300             rtpqdm2depay->framesize = GST_READ_UINT32_BE (payload + pos + 20);
301             rtpqdm2depay->packetsize = GST_READ_UINT32_BE (payload + pos + 24);
302             /* 16 bit empty block (0x02 0x00) */
303             pos += 30;
304             GST_DEBUG
305                 ("channs:%d, samplerate:%d, bitrate:%d, blocksize:%d, framesize:%d, packetsize:%d",
306                 rtpqdm2depay->channs, rtpqdm2depay->samplerate,
307                 rtpqdm2depay->bitrate, rtpqdm2depay->blocksize,
308                 rtpqdm2depay->framesize, rtpqdm2depay->packetsize);
309
310             /* Caps */
311             codecdata = gst_buffer_new_and_alloc (48);
312             memcpy (GST_BUFFER_DATA (codecdata), headheader, 20);
313             memcpy (GST_BUFFER_DATA (codecdata) + 20, ourdata, 28);
314
315             caps = gst_caps_new_simple ("audio/x-qdm2",
316                 "samplesize", G_TYPE_INT, 16,
317                 "rate", G_TYPE_INT, rtpqdm2depay->samplerate,
318                 "channels", G_TYPE_INT, rtpqdm2depay->channs,
319                 "codec_data", GST_TYPE_BUFFER, codecdata, NULL);
320             gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD_SRCPAD (depayload), caps);
321             gst_caps_unref (caps);
322             rtpqdm2depay->configured = TRUE;
323           } else {
324             GST_DEBUG ("Already configured, skipping headers");
325             pos += 40;
326           }
327           break;
328         default:{
329           /* Shuffled packet contents */
330           guint packetid = payload[pos++];
331           guint packettype = payload[pos++];
332           guint packlen = payload[pos++];
333           guint hsize = 2;
334
335           GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
336               packetid, packettype, packlen);
337
338           /* Packets bigger than 0xff bytes have a type with the high bit set */
339           if (G_UNLIKELY (packettype & 0x80)) {
340             packettype &= 0x7f;
341             packlen <<= 8;
342             packlen |= payload[pos++];
343             hsize = 3;
344             GST_DEBUG ("Packet id:%d, type:0x%x, len:%d",
345                 packetid, packettype, packlen);
346           }
347
348           if (packettype > 0x7f) {
349             GST_ERROR ("HOUSTON WE HAVE A PROBLEM !!!!");
350           }
351           add_packet (rtpqdm2depay, packetid, packlen + hsize,
352               payload + pos - hsize);
353           pos += packlen;
354         }
355       }
356     }
357
358     GST_DEBUG ("final pos %d", pos);
359
360     avail = gst_adapter_available (rtpqdm2depay->adapter);
361     if (G_UNLIKELY (avail)) {
362       GST_DEBUG ("Pushing out %d bytes of collected data", avail);
363       outbuf = gst_adapter_take_buffer (rtpqdm2depay->adapter, avail);
364       GST_BUFFER_TIMESTAMP (outbuf) = rtpqdm2depay->ptimestamp;
365       GST_DEBUG ("Outgoing buffer timestamp %" GST_TIME_FORMAT,
366           GST_TIME_ARGS (rtpqdm2depay->ptimestamp));
367       return outbuf;
368     }
369   }
370   return NULL;
371
372   /* ERRORS */
373 bad_packet:
374   {
375     GST_ELEMENT_WARNING (rtpqdm2depay, STREAM, DECODE,
376         (NULL), ("Packet was too short"));
377     return NULL;
378   }
379 }
380
381 static GstStateChangeReturn
382 gst_rtp_qdm2_depay_change_state (GstElement * element,
383     GstStateChange transition)
384 {
385   GstRtpQDM2Depay *rtpqdm2depay;
386   GstStateChangeReturn ret;
387
388   rtpqdm2depay = GST_RTP_QDM2_DEPAY (element);
389
390   switch (transition) {
391     case GST_STATE_CHANGE_NULL_TO_READY:
392       break;
393     case GST_STATE_CHANGE_READY_TO_PAUSED:
394       gst_adapter_clear (rtpqdm2depay->adapter);
395       break;
396     default:
397       break;
398   }
399
400   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
401
402   switch (transition) {
403     case GST_STATE_CHANGE_READY_TO_NULL:
404       break;
405     default:
406       break;
407   }
408   return ret;
409 }
410
411 gboolean
412 gst_rtp_qdm2_depay_plugin_init (GstPlugin * plugin)
413 {
414   GST_DEBUG_CATEGORY_INIT (rtpqdm2depay_debug, "rtpqdm2depay", 0,
415       "RTP QDM2 depayloader");
416
417   return gst_element_register (plugin, "rtpqdm2depay",
418       GST_RANK_SECONDARY, GST_TYPE_RTP_QDM2_DEPAY);
419 }