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