rtpvorbisdepay: remove dead code
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpceltpay.c
1 /* GStreamer
2  * Copyright (C) <2009> 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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <gst/rtp/gstrtpbuffer.h>
27 #include <gst/audio/audio.h>
28
29 #include "gstrtpceltpay.h"
30 #include "gstrtputils.h"
31
32 GST_DEBUG_CATEGORY_STATIC (rtpceltpay_debug);
33 #define GST_CAT_DEFAULT (rtpceltpay_debug)
34
35 static GstStaticPadTemplate gst_rtp_celt_pay_sink_template =
36 GST_STATIC_PAD_TEMPLATE ("sink",
37     GST_PAD_SINK,
38     GST_PAD_ALWAYS,
39     GST_STATIC_CAPS ("audio/x-celt, "
40         "rate = (int) [ 32000, 64000 ], "
41         "channels = (int) [1, 2], " "frame-size = (int) [ 64, 512 ]")
42     );
43
44 static GstStaticPadTemplate gst_rtp_celt_pay_src_template =
45 GST_STATIC_PAD_TEMPLATE ("src",
46     GST_PAD_SRC,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS ("application/x-rtp, "
49         "media = (string) \"audio\", "
50         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
51         "clock-rate =  (int) [ 32000, 48000 ], "
52         "encoding-name = (string) \"CELT\"")
53     );
54
55 static void gst_rtp_celt_pay_finalize (GObject * object);
56
57 static GstStateChangeReturn gst_rtp_celt_pay_change_state (GstElement *
58     element, GstStateChange transition);
59
60 static gboolean gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload,
61     GstCaps * caps);
62 static GstCaps *gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload,
63     GstPad * pad, GstCaps * filter);
64 static GstFlowReturn gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload *
65     payload, GstBuffer * buffer);
66
67 #define gst_rtp_celt_pay_parent_class parent_class
68 G_DEFINE_TYPE (GstRtpCELTPay, gst_rtp_celt_pay, GST_TYPE_RTP_BASE_PAYLOAD);
69
70 static void
71 gst_rtp_celt_pay_class_init (GstRtpCELTPayClass * klass)
72 {
73   GObjectClass *gobject_class;
74   GstElementClass *gstelement_class;
75   GstRTPBasePayloadClass *gstrtpbasepayload_class;
76
77   GST_DEBUG_CATEGORY_INIT (rtpceltpay_debug, "rtpceltpay", 0,
78       "CELT RTP Payloader");
79
80   gobject_class = (GObjectClass *) klass;
81   gstelement_class = (GstElementClass *) klass;
82   gstrtpbasepayload_class = (GstRTPBasePayloadClass *) klass;
83
84   gobject_class->finalize = gst_rtp_celt_pay_finalize;
85
86   gstelement_class->change_state = gst_rtp_celt_pay_change_state;
87
88   gst_element_class_add_static_pad_template (gstelement_class,
89       &gst_rtp_celt_pay_sink_template);
90   gst_element_class_add_static_pad_template (gstelement_class,
91       &gst_rtp_celt_pay_src_template);
92
93   gst_element_class_set_static_metadata (gstelement_class, "RTP CELT payloader",
94       "Codec/Payloader/Network/RTP",
95       "Payload-encodes CELT audio into a RTP packet",
96       "Wim Taymans <wim.taymans@gmail.com>");
97
98   gstrtpbasepayload_class->set_caps = gst_rtp_celt_pay_setcaps;
99   gstrtpbasepayload_class->get_caps = gst_rtp_celt_pay_getcaps;
100   gstrtpbasepayload_class->handle_buffer = gst_rtp_celt_pay_handle_buffer;
101 }
102
103 static void
104 gst_rtp_celt_pay_init (GstRtpCELTPay * rtpceltpay)
105 {
106   rtpceltpay->queue = g_queue_new ();
107 }
108
109 static void
110 gst_rtp_celt_pay_finalize (GObject * object)
111 {
112   GstRtpCELTPay *rtpceltpay;
113
114   rtpceltpay = GST_RTP_CELT_PAY (object);
115
116   g_queue_free (rtpceltpay->queue);
117
118   G_OBJECT_CLASS (parent_class)->finalize (object);
119 }
120
121 static void
122 gst_rtp_celt_pay_clear_queued (GstRtpCELTPay * rtpceltpay)
123 {
124   GstBuffer *buf;
125
126   while ((buf = g_queue_pop_head (rtpceltpay->queue)))
127     gst_buffer_unref (buf);
128
129   rtpceltpay->bytes = 0;
130   rtpceltpay->sbytes = 0;
131   rtpceltpay->qduration = 0;
132 }
133
134 static void
135 gst_rtp_celt_pay_add_queued (GstRtpCELTPay * rtpceltpay, GstBuffer * buffer,
136     guint ssize, guint size, GstClockTime duration)
137 {
138   g_queue_push_tail (rtpceltpay->queue, buffer);
139   rtpceltpay->sbytes += ssize;
140   rtpceltpay->bytes += size;
141   /* only add durations when we have a valid previous duration */
142   if (rtpceltpay->qduration != -1) {
143     if (duration != -1)
144       /* only add valid durations */
145       rtpceltpay->qduration += duration;
146     else
147       /* if we add a buffer without valid duration, our total queued duration
148        * becomes unknown */
149       rtpceltpay->qduration = -1;
150   }
151 }
152
153 static gboolean
154 gst_rtp_celt_pay_setcaps (GstRTPBasePayload * payload, GstCaps * caps)
155 {
156   /* don't configure yet, we wait for the ident packet */
157   return TRUE;
158 }
159
160
161 static GstCaps *
162 gst_rtp_celt_pay_getcaps (GstRTPBasePayload * payload, GstPad * pad,
163     GstCaps * filter)
164 {
165   GstCaps *otherpadcaps;
166   GstCaps *caps;
167   const gchar *params;
168
169   caps = gst_pad_get_pad_template_caps (pad);
170
171   otherpadcaps = gst_pad_get_allowed_caps (payload->srcpad);
172   if (otherpadcaps) {
173     if (!gst_caps_is_empty (otherpadcaps)) {
174       GstStructure *ps;
175       GstStructure *s;
176       gint clock_rate = 0, frame_size = 0, channels = 1;
177
178       caps = gst_caps_make_writable (caps);
179
180       ps = gst_caps_get_structure (otherpadcaps, 0);
181       s = gst_caps_get_structure (caps, 0);
182
183       if (gst_structure_get_int (ps, "clock-rate", &clock_rate)) {
184         gst_structure_fixate_field_nearest_int (s, "rate", clock_rate);
185       }
186
187       if ((params = gst_structure_get_string (ps, "frame-size")))
188         frame_size = atoi (params);
189       if (frame_size)
190         gst_structure_set (s, "frame-size", G_TYPE_INT, frame_size, NULL);
191
192       if ((params = gst_structure_get_string (ps, "encoding-params"))) {
193         channels = atoi (params);
194         gst_structure_fixate_field_nearest_int (s, "channels", channels);
195       }
196
197       GST_DEBUG_OBJECT (payload, "clock-rate=%d frame-size=%d channels=%d",
198           clock_rate, frame_size, channels);
199     }
200     gst_caps_unref (otherpadcaps);
201   }
202
203   return caps;
204 }
205
206 static gboolean
207 gst_rtp_celt_pay_parse_ident (GstRtpCELTPay * rtpceltpay,
208     const guint8 * data, guint size)
209 {
210   guint32 version, header_size, rate, nb_channels, frame_size, overlap;
211   guint32 bytes_per_packet;
212   GstRTPBasePayload *payload;
213   gchar *cstr, *fsstr;
214   gboolean res;
215
216   /* we need the header string (8), the version string (20), the version
217    * and the header length. */
218   if (size < 36)
219     goto too_small;
220
221   if (!g_str_has_prefix ((const gchar *) data, "CELT    "))
222     goto wrong_header;
223
224   /* skip header and version string */
225   data += 28;
226
227   version = GST_READ_UINT32_LE (data);
228   GST_DEBUG_OBJECT (rtpceltpay, "version %08x", version);
229 #if 0
230   if (version != 1)
231     goto wrong_version;
232 #endif
233
234   data += 4;
235   /* ensure sizes */
236   header_size = GST_READ_UINT32_LE (data);
237   if (header_size < 56)
238     goto header_too_small;
239
240   if (size < header_size)
241     goto payload_too_small;
242
243   data += 4;
244   rate = GST_READ_UINT32_LE (data);
245   data += 4;
246   nb_channels = GST_READ_UINT32_LE (data);
247   data += 4;
248   frame_size = GST_READ_UINT32_LE (data);
249   data += 4;
250   overlap = GST_READ_UINT32_LE (data);
251   data += 4;
252   bytes_per_packet = GST_READ_UINT32_LE (data);
253
254   GST_DEBUG_OBJECT (rtpceltpay, "rate %d, nb_channels %d, frame_size %d",
255       rate, nb_channels, frame_size);
256   GST_DEBUG_OBJECT (rtpceltpay, "overlap %d, bytes_per_packet %d",
257       overlap, bytes_per_packet);
258
259   payload = GST_RTP_BASE_PAYLOAD (rtpceltpay);
260
261   gst_rtp_base_payload_set_options (payload, "audio", FALSE, "CELT", rate);
262   cstr = g_strdup_printf ("%d", nb_channels);
263   fsstr = g_strdup_printf ("%d", frame_size);
264   res = gst_rtp_base_payload_set_outcaps (payload, "encoding-params",
265       G_TYPE_STRING, cstr, "frame-size", G_TYPE_STRING, fsstr, NULL);
266   g_free (cstr);
267   g_free (fsstr);
268
269   return res;
270
271   /* ERRORS */
272 too_small:
273   {
274     GST_DEBUG_OBJECT (rtpceltpay,
275         "ident packet too small, need at least 32 bytes");
276     return FALSE;
277   }
278 wrong_header:
279   {
280     GST_DEBUG_OBJECT (rtpceltpay,
281         "ident packet does not start with \"CELT    \"");
282     return FALSE;
283   }
284 #if 0
285 wrong_version:
286   {
287     GST_DEBUG_OBJECT (rtpceltpay, "can only handle version 1, have version %d",
288         version);
289     return FALSE;
290   }
291 #endif
292 header_too_small:
293   {
294     GST_DEBUG_OBJECT (rtpceltpay,
295         "header size too small, need at least 80 bytes, " "got only %d",
296         header_size);
297     return FALSE;
298   }
299 payload_too_small:
300   {
301     GST_DEBUG_OBJECT (rtpceltpay,
302         "payload too small, need at least %d bytes, got only %d", header_size,
303         size);
304     return FALSE;
305   }
306 }
307
308 static GstFlowReturn
309 gst_rtp_celt_pay_flush_queued (GstRtpCELTPay * rtpceltpay)
310 {
311   GstFlowReturn ret;
312   GstBuffer *buf, *outbuf;
313   guint8 *payload, *spayload;
314   guint payload_len;
315   GstClockTime duration;
316   GstRTPBuffer rtp = { NULL, };
317
318   payload_len = rtpceltpay->bytes + rtpceltpay->sbytes;
319   duration = rtpceltpay->qduration;
320
321   GST_DEBUG_OBJECT (rtpceltpay, "flushing out %u, duration %" GST_TIME_FORMAT,
322       payload_len, GST_TIME_ARGS (rtpceltpay->qduration));
323
324   /* get a big enough packet for the sizes + payloads */
325   outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
326
327   GST_BUFFER_DURATION (outbuf) = duration;
328
329   gst_rtp_buffer_map (outbuf, GST_MAP_WRITE, &rtp);
330
331   /* point to the payload for size headers and data */
332   spayload = gst_rtp_buffer_get_payload (&rtp);
333   payload = spayload + rtpceltpay->sbytes;
334
335   while ((buf = g_queue_pop_head (rtpceltpay->queue))) {
336     guint size;
337
338     /* copy first timestamp to output */
339     if (GST_BUFFER_PTS (outbuf) == -1)
340       GST_BUFFER_PTS (outbuf) = GST_BUFFER_PTS (buf);
341
342     /* write the size to the header */
343     size = gst_buffer_get_size (buf);
344     while (size > 0xff) {
345       *spayload++ = 0xff;
346       size -= 0xff;
347     }
348     *spayload++ = size;
349
350     /* copy payload */
351     size = gst_buffer_get_size (buf);
352     gst_buffer_extract (buf, 0, payload, size);
353     payload += size;
354
355     gst_rtp_copy_meta (GST_ELEMENT_CAST (rtpceltpay), outbuf, buf,
356         g_quark_from_static_string (GST_META_TAG_AUDIO_STR));
357
358     gst_buffer_unref (buf);
359   }
360   gst_rtp_buffer_unmap (&rtp);
361
362   /* we consumed it all */
363   rtpceltpay->bytes = 0;
364   rtpceltpay->sbytes = 0;
365   rtpceltpay->qduration = 0;
366
367   ret = gst_rtp_base_payload_push (GST_RTP_BASE_PAYLOAD (rtpceltpay), outbuf);
368
369   return ret;
370 }
371
372 static GstFlowReturn
373 gst_rtp_celt_pay_handle_buffer (GstRTPBasePayload * basepayload,
374     GstBuffer * buffer)
375 {
376   GstFlowReturn ret;
377   GstRtpCELTPay *rtpceltpay;
378   gsize payload_len;
379   GstMapInfo map;
380   GstClockTime duration, packet_dur;
381   guint i, ssize, packet_len;
382
383   rtpceltpay = GST_RTP_CELT_PAY (basepayload);
384
385   ret = GST_FLOW_OK;
386
387   gst_buffer_map (buffer, &map, GST_MAP_READ);
388
389   switch (rtpceltpay->packet) {
390     case 0:
391       /* ident packet. We need to parse the headers to construct the RTP
392        * properties. */
393       if (!gst_rtp_celt_pay_parse_ident (rtpceltpay, map.data, map.size))
394         goto parse_error;
395
396       goto cleanup;
397     case 1:
398       /* comment packet, we ignore it */
399       goto cleanup;
400     default:
401       /* other packets go in the payload */
402       break;
403   }
404   gst_buffer_unmap (buffer, &map);
405
406   duration = GST_BUFFER_DURATION (buffer);
407
408   GST_LOG_OBJECT (rtpceltpay,
409       "got buffer of duration %" GST_TIME_FORMAT ", size %" G_GSIZE_FORMAT,
410       GST_TIME_ARGS (duration), map.size);
411
412   /* calculate the size of the size field and the payload */
413   ssize = 1;
414   for (i = map.size; i > 0xff; i -= 0xff)
415     ssize++;
416
417   GST_DEBUG_OBJECT (rtpceltpay, "bytes for size %u", ssize);
418
419   /* calculate what the new size and duration would be of the packet */
420   payload_len = ssize + map.size + rtpceltpay->bytes + rtpceltpay->sbytes;
421   if (rtpceltpay->qduration != -1 && duration != -1)
422     packet_dur = rtpceltpay->qduration + duration;
423   else
424     packet_dur = 0;
425
426   packet_len = gst_rtp_buffer_calc_packet_len (payload_len, 0, 0);
427
428   if (gst_rtp_base_payload_is_filled (basepayload, packet_len, packet_dur)) {
429     /* size or duration would overflow the packet, flush the queued data */
430     ret = gst_rtp_celt_pay_flush_queued (rtpceltpay);
431   }
432
433   /* queue the packet */
434   gst_rtp_celt_pay_add_queued (rtpceltpay, buffer, ssize, map.size, duration);
435
436 done:
437   rtpceltpay->packet++;
438
439   return ret;
440
441   /* ERRORS */
442 cleanup:
443   {
444     gst_buffer_unmap (buffer, &map);
445     goto done;
446   }
447 parse_error:
448   {
449     GST_ELEMENT_ERROR (rtpceltpay, STREAM, DECODE, (NULL),
450         ("Error parsing first identification packet."));
451     gst_buffer_unmap (buffer, &map);
452     return GST_FLOW_ERROR;
453   }
454 }
455
456 static GstStateChangeReturn
457 gst_rtp_celt_pay_change_state (GstElement * element, GstStateChange transition)
458 {
459   GstRtpCELTPay *rtpceltpay;
460   GstStateChangeReturn ret;
461
462   rtpceltpay = GST_RTP_CELT_PAY (element);
463
464   switch (transition) {
465     case GST_STATE_CHANGE_NULL_TO_READY:
466       break;
467     case GST_STATE_CHANGE_READY_TO_PAUSED:
468       rtpceltpay->packet = 0;
469       break;
470     default:
471       break;
472   }
473
474   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
475
476   switch (transition) {
477     case GST_STATE_CHANGE_PAUSED_TO_READY:
478       gst_rtp_celt_pay_clear_queued (rtpceltpay);
479       break;
480     case GST_STATE_CHANGE_READY_TO_NULL:
481       break;
482     default:
483       break;
484   }
485   return ret;
486 }
487
488 gboolean
489 gst_rtp_celt_pay_plugin_init (GstPlugin * plugin)
490 {
491   return gst_element_register (plugin, "rtpceltpay",
492       GST_RANK_SECONDARY, GST_TYPE_RTP_CELT_PAY);
493 }