gst/rtp/: Fix caps with payload numbers.
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpmp4gpay.c
1 /* GStreamer
2  * Copyright (C) <2006> 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 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
28 #include "gstrtpmp4gpay.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpmp4gpay_debug);
31 #define GST_CAT_DEFAULT (rtpmp4gpay_debug)
32
33 /* elementfactory information */
34 static const GstElementDetails gst_rtp_mp4gpay_details =
35 GST_ELEMENT_DETAILS ("RTP packet payloader",
36     "Codec/Payloader/Network",
37     "Payload MPEG4 elementary streams as RTP packets (RFC 3640)",
38     "Wim Taymans <wim@fluendo.com>");
39
40 static GstStaticPadTemplate gst_rtp_mp4g_pay_sink_template =
41     GST_STATIC_PAD_TEMPLATE ("sink",
42     GST_PAD_SINK,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("video/mpeg,"
45         "mpegversion=(int) 4,"
46         "systemstream=(boolean)false;" "audio/mpeg," "mpegversion=(int) 4")
47     );
48
49 static GstStaticPadTemplate gst_rtp_mp4g_pay_src_template =
50 GST_STATIC_PAD_TEMPLATE ("src",
51     GST_PAD_SRC,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS ("application/x-rtp, "
54         "media = (string) { \"video\", \"audio\", \"application\" }, "
55         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
56         "clock-rate = (int) [1, MAX ], "
57         "encoding-name = (string) \"mpeg4-generic\", "
58         /* required string params */
59         "streamtype = (string) { \"4\", \"5\" }, "      /* 4 = video, 5 = audio */
60         /* "profile-level-id = (string) [1,MAX], " */
61         /* "config = (string) [1,MAX]" */
62         "mode = (string) { \"generic\", \"CELP-cbr\", \"CELP-vbr\", \"AAC-lbr\", \"AAC-hbr\" } "
63         /* Optional general parameters */
64         /* "objecttype = (string) [1,MAX], " */
65         /* "constantsize = (string) [1,MAX], " *//* constant size of each AU */
66         /* "constantduration = (string) [1,MAX], " *//* constant duration of each AU */
67         /* "maxdisplacement = (string) [1,MAX], " */
68         /* "de-interleavebuffersize = (string) [1,MAX], " */
69         /* Optional configuration parameters */
70         /* "sizelength = (string) [1, 16], " *//* max 16 bits, should be enough... */
71         /* "indexlength = (string) [1, 8], " */
72         /* "indexdeltalength = (string) [1, 8], " */
73         /* "ctsdeltalength = (string) [1, 64], " */
74         /* "dtsdeltalength = (string) [1, 64], " */
75         /* "randomaccessindication = (string) {0, 1}, " */
76         /* "streamstateindication = (string) [0, 64], " */
77         /* "auxiliarydatasizelength = (string) [0, 64]" */ )
78     );
79
80 enum
81 {
82   PROP_0,
83 };
84
85
86 static void gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass);
87 static void gst_rtp_mp4g_pay_base_init (GstRtpMP4GPayClass * klass);
88 static void gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay);
89 static void gst_rtp_mp4g_pay_finalize (GObject * object);
90
91 static void gst_rtp_mp4g_pay_set_property (GObject * object, guint prop_id,
92     const GValue * value, GParamSpec * pspec);
93 static void gst_rtp_mp4g_pay_get_property (GObject * object, guint prop_id,
94     GValue * value, GParamSpec * pspec);
95
96 static gboolean gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload,
97     GstCaps * caps);
98 static GstFlowReturn gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload *
99     payload, GstBuffer * buffer);
100
101 static GstBaseRTPPayloadClass *parent_class = NULL;
102
103 static GType
104 gst_rtp_mp4g_pay_get_type (void)
105 {
106   static GType rtpmp4gpay_type = 0;
107
108   if (!rtpmp4gpay_type) {
109     static const GTypeInfo rtpmp4gpay_info = {
110       sizeof (GstRtpMP4GPayClass),
111       (GBaseInitFunc) gst_rtp_mp4g_pay_base_init,
112       NULL,
113       (GClassInitFunc) gst_rtp_mp4g_pay_class_init,
114       NULL,
115       NULL,
116       sizeof (GstRtpMP4GPay),
117       0,
118       (GInstanceInitFunc) gst_rtp_mp4g_pay_init,
119     };
120
121     rtpmp4gpay_type =
122         g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMP4GPay",
123         &rtpmp4gpay_info, 0);
124   }
125   return rtpmp4gpay_type;
126 }
127
128 static void
129 gst_rtp_mp4g_pay_base_init (GstRtpMP4GPayClass * klass)
130 {
131   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
132
133   gst_element_class_add_pad_template (element_class,
134       gst_static_pad_template_get (&gst_rtp_mp4g_pay_src_template));
135   gst_element_class_add_pad_template (element_class,
136       gst_static_pad_template_get (&gst_rtp_mp4g_pay_sink_template));
137
138   gst_element_class_set_details (element_class, &gst_rtp_mp4gpay_details);
139 }
140
141 static void
142 gst_rtp_mp4g_pay_class_init (GstRtpMP4GPayClass * klass)
143 {
144   GObjectClass *gobject_class;
145   GstElementClass *gstelement_class;
146   GstBaseRTPPayloadClass *gstbasertppayload_class;
147
148   gobject_class = (GObjectClass *) klass;
149   gstelement_class = (GstElementClass *) klass;
150   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
151
152   parent_class = g_type_class_peek_parent (klass);
153
154   gobject_class->set_property = gst_rtp_mp4g_pay_set_property;
155   gobject_class->get_property = gst_rtp_mp4g_pay_get_property;
156
157   gobject_class->finalize = gst_rtp_mp4g_pay_finalize;
158
159   gstbasertppayload_class->set_caps = gst_rtp_mp4g_pay_setcaps;
160   gstbasertppayload_class->handle_buffer = gst_rtp_mp4g_pay_handle_buffer;
161
162   GST_DEBUG_CATEGORY_INIT (rtpmp4gpay_debug, "rtpmp4gpay", 0,
163       "MP4-generic RTP Payloader");
164 }
165
166 static void
167 gst_rtp_mp4g_pay_init (GstRtpMP4GPay * rtpmp4gpay)
168 {
169   rtpmp4gpay->adapter = gst_adapter_new ();
170   rtpmp4gpay->rate = 90000;
171   rtpmp4gpay->profile = g_strdup ("1");
172   rtpmp4gpay->mode = "";
173 }
174
175 static void
176 gst_rtp_mp4g_pay_finalize (GObject * object)
177 {
178   GstRtpMP4GPay *rtpmp4gpay;
179
180   rtpmp4gpay = GST_RTP_MP4G_PAY (object);
181
182   g_object_unref (rtpmp4gpay->adapter);
183   rtpmp4gpay->adapter = NULL;
184   g_free (rtpmp4gpay->params);
185   rtpmp4gpay->params = NULL;
186
187   G_OBJECT_CLASS (parent_class)->finalize (object);
188 }
189
190 static unsigned sampling_table[16] = {
191   96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
192   16000, 12000, 11025, 8000, 7350, 0, 0, 0
193 };
194
195 static gboolean
196 gst_rtp_mp4g_pay_parse_audio_config (GstRtpMP4GPay * rtpmp4gpay,
197     GstBuffer * buffer)
198 {
199   guint8 *data;
200   guint size;
201   guint8 objectType;
202   guint8 samplingIdx;
203   guint8 channelCfg;
204
205   data = GST_BUFFER_DATA (buffer);
206   size = GST_BUFFER_SIZE (buffer);
207
208   if (size < 2)
209     goto too_short;
210
211   /* any object type is fine, we need to copy it to the profile-level-id field. */
212   objectType = (data[0] & 0xf8) >> 3;
213   if (objectType == 0)
214     goto invalid_object;
215
216   samplingIdx = ((data[0] & 0x07) << 1) | ((data[1] & 0x80) >> 7);
217   /* only fixed values for now */
218   if (samplingIdx > 12 && samplingIdx != 15)
219     goto wrong_freq;
220
221   channelCfg = ((data[1] & 0x78) >> 3);
222   if (channelCfg > 7)
223     goto wrong_channels;
224
225   /* rtp rate depends on sampling rate of the audio */
226   if (samplingIdx == 15) {
227     if (size < 5)
228       goto too_short;
229
230     /* index of 15 means we get the rate in the next 24 bits */
231     rtpmp4gpay->rate = ((data[1] & 0x7f) << 17) |
232         ((data[2]) << 9) | ((data[3]) << 1) | ((data[4] & 0x80) >> 7);
233   } else {
234     /* else use the rate from the table */
235     rtpmp4gpay->rate = sampling_table[samplingIdx];
236   }
237   /* extra rtp params contain the number of channels */
238   g_free (rtpmp4gpay->params);
239   rtpmp4gpay->params = g_strdup_printf ("%d", channelCfg);
240   /* audio stream type */
241   rtpmp4gpay->streamtype = "5";
242   /* mode only high bitrate for now */
243   rtpmp4gpay->mode = "AAC-hbr";
244   /* profile */
245   g_free (rtpmp4gpay->profile);
246   rtpmp4gpay->profile = g_strdup_printf ("%d", objectType);
247
248   GST_DEBUG_OBJECT (rtpmp4gpay,
249       "objectType: %d, samplingIdx: %d (%d), channelCfg: %d", objectType,
250       samplingIdx, rtpmp4gpay->rate, channelCfg);
251
252   return TRUE;
253
254   /* ERROR */
255 too_short:
256   {
257     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
258         (NULL), ("config string too short, expected 2 bytes, got %d", size));
259     return FALSE;
260   }
261 invalid_object:
262   {
263     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
264         (NULL), ("invalid object type 0"));
265     return FALSE;
266   }
267 wrong_freq:
268   {
269     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
270         (NULL), ("unsupported frequency index %d", samplingIdx));
271     return FALSE;
272   }
273 wrong_channels:
274   {
275     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, NOT_IMPLEMENTED,
276         (NULL), ("unsupported number of channels %d, must < 8", channelCfg));
277     return FALSE;
278   }
279 }
280
281 #define VOS_STARTCODE                   0x000001B0
282
283 static gboolean
284 gst_rtp_mp4g_pay_parse_video_config (GstRtpMP4GPay * rtpmp4gpay,
285     GstBuffer * buffer)
286 {
287   guint8 *data;
288   guint size;
289   guint32 code;
290
291   data = GST_BUFFER_DATA (buffer);
292   size = GST_BUFFER_SIZE (buffer);
293
294   if (size < 5)
295     goto too_short;
296
297   code = GST_READ_UINT32_BE (data);
298
299   g_free (rtpmp4gpay->profile);
300   if (code == VOS_STARTCODE) {
301     /* get profile */
302     rtpmp4gpay->profile = g_strdup_printf ("%d", (gint) data[4]);
303   } else {
304     GST_ELEMENT_WARNING (rtpmp4gpay, STREAM, FORMAT,
305         (NULL), ("profile not found in config string, assuming \'1\'"));
306     rtpmp4gpay->profile = g_strdup ("1");
307   }
308
309   /* fixed rate */
310   rtpmp4gpay->rate = 90000;
311   /* video stream type */
312   rtpmp4gpay->streamtype = "4";
313   /* no params for video */
314   rtpmp4gpay->params = NULL;
315   /* mode */
316   rtpmp4gpay->mode = "generic";
317
318   GST_LOG_OBJECT (rtpmp4gpay, "profile %s", rtpmp4gpay->profile);
319
320   return TRUE;
321
322   /* ERROR */
323 too_short:
324   {
325     GST_ELEMENT_ERROR (rtpmp4gpay, STREAM, FORMAT,
326         (NULL), ("config string too short"));
327     return FALSE;
328   }
329 }
330
331 static void
332 gst_rtp_mp4g_pay_new_caps (GstRtpMP4GPay * rtpmp4gpay)
333 {
334   gchar *config;
335   GValue v = { 0 };
336
337 #define MP4GCAPS                                                \
338   "streamtype", G_TYPE_STRING, rtpmp4gpay->streamtype,          \
339   "profile-level-id", G_TYPE_STRING, rtpmp4gpay->profile,       \
340   "mode", G_TYPE_STRING, rtpmp4gpay->mode,                      \
341   "config", G_TYPE_STRING, config,                              \
342   "sizelength", G_TYPE_STRING, "13",                            \
343   "indexlength", G_TYPE_STRING, "3",                            \
344   "indexdeltalength", G_TYPE_STRING, "3",                       \
345   NULL
346
347   g_value_init (&v, GST_TYPE_BUFFER);
348   gst_value_set_buffer (&v, rtpmp4gpay->config);
349   config = gst_value_serialize (&v);
350
351   /* hmm, silly */
352   if (rtpmp4gpay->params) {
353     gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4gpay),
354         "encoding-params", G_TYPE_STRING, rtpmp4gpay->params, MP4GCAPS);
355   } else {
356     gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4gpay),
357         MP4GCAPS);
358   }
359
360   g_value_unset (&v);
361   g_free (config);
362
363 #undef MP4GCAPS
364 }
365
366 static gboolean
367 gst_rtp_mp4g_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
368 {
369   GstRtpMP4GPay *rtpmp4gpay;
370   GstStructure *structure;
371   const GValue *codec_data;
372   gchar *media_type = NULL;
373
374   rtpmp4gpay = GST_RTP_MP4G_PAY (payload);
375
376   structure = gst_caps_get_structure (caps, 0);
377
378   codec_data = gst_structure_get_value (structure, "codec_data");
379   if (codec_data) {
380     GST_LOG_OBJECT (rtpmp4gpay, "got codec_data");
381     if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
382       GstBuffer *buffer;
383       const gchar *name;
384       gboolean res;
385
386       buffer = gst_value_get_buffer (codec_data);
387       GST_LOG_OBJECT (rtpmp4gpay, "configuring codec_data");
388
389       name = gst_structure_get_name (structure);
390
391       /* parse buffer */
392       if (!strcmp (name, "audio/mpeg")) {
393         res = gst_rtp_mp4g_pay_parse_audio_config (rtpmp4gpay, buffer);
394         media_type = "audio";
395       } else if (!strcmp (name, "video/mpeg")) {
396         res = gst_rtp_mp4g_pay_parse_video_config (rtpmp4gpay, buffer);
397         media_type = "video";
398       } else {
399         res = FALSE;
400       }
401       if (!res)
402         goto config_failed;
403
404       /* now we can configure the buffer */
405       if (rtpmp4gpay->config)
406         gst_buffer_unref (rtpmp4gpay->config);
407
408       rtpmp4gpay->config = gst_buffer_copy (buffer);
409     }
410   }
411   if (media_type == NULL)
412     goto config_failed;
413
414   gst_basertppayload_set_options (payload, media_type, TRUE, "mpeg4-generic",
415       rtpmp4gpay->rate);
416
417   gst_rtp_mp4g_pay_new_caps (rtpmp4gpay);
418
419   return TRUE;
420
421   /* ERRORS */
422 config_failed:
423   {
424     GST_DEBUG_OBJECT (rtpmp4gpay, "failed to parse config");
425     return FALSE;
426   }
427 }
428
429 static GstFlowReturn
430 gst_rtp_mp4g_pay_flush (GstRtpMP4GPay * rtpmp4gpay)
431 {
432   guint avail, total;
433   GstBuffer *outbuf;
434   GstFlowReturn ret;
435   gboolean fragmented;
436   guint mtu;
437
438   fragmented = FALSE;
439
440   /* the data available in the adapter is either smaller
441    * than the MTU or bigger. In the case it is smaller, the complete
442    * adapter contents can be put in one packet. In the case the
443    * adapter has more than one MTU, we need to fragment the MPEG data
444    * over multiple packets. */
445   total = avail = gst_adapter_available (rtpmp4gpay->adapter);
446
447   ret = GST_FLOW_OK;
448   mtu = GST_BASE_RTP_PAYLOAD_MTU (rtpmp4gpay);
449
450   while (avail > 0) {
451     guint towrite;
452     guint8 *payload;
453     guint8 *data;
454     guint payload_len;
455     guint packet_len;
456
457     /* this will be the total lenght of the packet */
458     packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
459
460     /* fill one MTU or all available bytes, we need 4 spare bytes for
461      * the AU header. */
462     towrite = MIN (packet_len, mtu - 4);
463
464     /* this is the payload length */
465     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
466
467     GST_DEBUG_OBJECT (rtpmp4gpay,
468         "avail %d, towrite %d, packet_len %d, payload_len %d", avail, towrite,
469         packet_len, payload_len);
470
471     /* create buffer to hold the payload, also make room for the 4 header bytes. */
472     outbuf = gst_rtp_buffer_new_allocate (payload_len + 4, 0, 0);
473
474     /* copy payload */
475     payload = gst_rtp_buffer_get_payload (outbuf);
476
477     /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
478      * |AU-headers-length|AU-header|AU-header|      |AU-header|padding|
479      * |                 |   (1)   |   (2)   |      |   (n)   | bits  |
480      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- .. -+-+-+-+-+-+-+-+-+-+
481      */
482     /* AU-headers-length, we only have 1 AU-header */
483     payload[0] = 0x00;
484     payload[1] = 0x10;          /* we use 16 bits for the header */
485
486     /* +---------------------------------------+
487      * |     AU-size                           |
488      * +---------------------------------------+
489      * |     AU-Index / AU-Index-delta         |
490      * +---------------------------------------+
491      * |     CTS-flag                          |
492      * +---------------------------------------+
493      * |     CTS-delta                         |
494      * +---------------------------------------+
495      * |     DTS-flag                          |
496      * +---------------------------------------+
497      * |     DTS-delta                         |
498      * +---------------------------------------+
499      * |     RAP-flag                          |
500      * +---------------------------------------+
501      * |     Stream-state                      |
502      * +---------------------------------------+
503      */
504     /* The AU-header, no CTS, DTS, RAP, Stream-state 
505      *
506      * AU-size is always the total size of the AU, not the fragmented size 
507      */
508     payload[2] = (total & 0x1fe0) >> 5;
509     payload[3] = (total & 0x1f) << 3;   /* we use 13 bits for the size, 3 bits index */
510
511     data = (guint8 *) gst_adapter_peek (rtpmp4gpay->adapter, payload_len);
512     memcpy (&payload[4], data, payload_len);
513
514     gst_adapter_flush (rtpmp4gpay->adapter, payload_len);
515
516     /* marker only if the packet is complete */
517     gst_rtp_buffer_set_marker (outbuf, avail <= payload_len);
518
519     GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4gpay->first_ts;
520
521     ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4gpay), outbuf);
522
523     avail -= payload_len;
524     fragmented = TRUE;
525   }
526
527   return ret;
528 }
529
530 /* we expect buffers as exactly one complete AU
531  */
532 static GstFlowReturn
533 gst_rtp_mp4g_pay_handle_buffer (GstBaseRTPPayload * basepayload,
534     GstBuffer * buffer)
535 {
536   GstRtpMP4GPay *rtpmp4gpay;
537   GstFlowReturn ret;
538
539   ret = GST_FLOW_OK;
540
541   rtpmp4gpay = GST_RTP_MP4G_PAY (basepayload);
542
543   rtpmp4gpay->first_ts = GST_BUFFER_TIMESTAMP (buffer);
544
545   /* we always encode and flush a full AU */
546   gst_adapter_push (rtpmp4gpay->adapter, buffer);
547   ret = gst_rtp_mp4g_pay_flush (rtpmp4gpay);
548
549   return ret;
550 }
551
552 static void
553 gst_rtp_mp4g_pay_set_property (GObject * object, guint prop_id,
554     const GValue * value, GParamSpec * pspec)
555 {
556   GstRtpMP4GPay *rtpmp4gpay;
557
558   rtpmp4gpay = GST_RTP_MP4G_PAY (object);
559
560   switch (prop_id) {
561     default:
562       break;
563   }
564 }
565
566 static void
567 gst_rtp_mp4g_pay_get_property (GObject * object, guint prop_id,
568     GValue * value, GParamSpec * pspec)
569 {
570   GstRtpMP4GPay *rtpmp4gpay;
571
572   rtpmp4gpay = GST_RTP_MP4G_PAY (object);
573
574   switch (prop_id) {
575     default:
576       break;
577   }
578 }
579
580 gboolean
581 gst_rtp_mp4g_pay_plugin_init (GstPlugin * plugin)
582 {
583   return gst_element_register (plugin, "rtpmp4gpay",
584       GST_RANK_NONE, GST_TYPE_RTP_MP4G_PAY);
585 }