01e7f2a08ecac1cf0e0ae59460a8f25c02ace7ea
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpmp4vpay.c
1 /* GStreamer
2  * Copyright (C) <2005> 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., 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 "gstrtpmp4vpay.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpmp4vpay_debug);
31 #define GST_CAT_DEFAULT (rtpmp4vpay_debug)
32
33 /* elementfactory information */
34 static const GstElementDetails gst_rtp_mp4vpay_details =
35 GST_ELEMENT_DETAILS ("RTP MPEG4 Video payloader",
36     "Codec/Payloader/Network",
37     "Payload MPEG-4 video as RTP packets (RFC 3016)",
38     "Wim Taymans <wim.taymans@gmail.com>");
39
40 static GstStaticPadTemplate gst_rtp_mp4v_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," "systemstream=(boolean)false")
46     );
47
48 static GstStaticPadTemplate gst_rtp_mp4v_pay_src_template =
49 GST_STATIC_PAD_TEMPLATE ("src",
50     GST_PAD_SRC,
51     GST_PAD_ALWAYS,
52     GST_STATIC_CAPS ("application/x-rtp, "
53         "media = (string) \"video\", "
54         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
55         "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"MP4V-ES\""
56         /* two string params
57          *
58          "profile-level-id = (string) [1,MAX]"
59          "config = (string) [1,MAX]"
60          */
61     )
62     );
63
64 #define DEFAULT_SEND_CONFIG     FALSE
65
66 enum
67 {
68   ARG_0,
69   ARG_SEND_CONFIG
70 };
71
72
73 static void gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass);
74 static void gst_rtp_mp4v_pay_base_init (GstRtpMP4VPayClass * klass);
75 static void gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay);
76 static void gst_rtp_mp4v_pay_finalize (GObject * object);
77
78 static void gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
79     const GValue * value, GParamSpec * pspec);
80 static void gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
81     GValue * value, GParamSpec * pspec);
82
83 static gboolean gst_rtp_mp4v_pay_setcaps (GstBaseRTPPayload * payload,
84     GstCaps * caps);
85 static GstFlowReturn gst_rtp_mp4v_pay_handle_buffer (GstBaseRTPPayload *
86     payload, GstBuffer * buffer);
87 static gboolean gst_rtp_mp4v_pay_event (GstPad * pad, GstEvent * event);
88
89 static GstBaseRTPPayloadClass *parent_class = NULL;
90
91 static GType
92 gst_rtp_mp4v_pay_get_type (void)
93 {
94   static GType rtpmp4vpay_type = 0;
95
96   if (!rtpmp4vpay_type) {
97     static const GTypeInfo rtpmp4vpay_info = {
98       sizeof (GstRtpMP4VPayClass),
99       (GBaseInitFunc) gst_rtp_mp4v_pay_base_init,
100       NULL,
101       (GClassInitFunc) gst_rtp_mp4v_pay_class_init,
102       NULL,
103       NULL,
104       sizeof (GstRtpMP4VPay),
105       0,
106       (GInstanceInitFunc) gst_rtp_mp4v_pay_init,
107     };
108
109     rtpmp4vpay_type =
110         g_type_register_static (GST_TYPE_BASE_RTP_PAYLOAD, "GstRtpMP4VPay",
111         &rtpmp4vpay_info, 0);
112   }
113   return rtpmp4vpay_type;
114 }
115
116 static void
117 gst_rtp_mp4v_pay_base_init (GstRtpMP4VPayClass * klass)
118 {
119   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
120
121   gst_element_class_add_pad_template (element_class,
122       gst_static_pad_template_get (&gst_rtp_mp4v_pay_src_template));
123   gst_element_class_add_pad_template (element_class,
124       gst_static_pad_template_get (&gst_rtp_mp4v_pay_sink_template));
125
126   gst_element_class_set_details (element_class, &gst_rtp_mp4vpay_details);
127 }
128
129 static void
130 gst_rtp_mp4v_pay_class_init (GstRtpMP4VPayClass * klass)
131 {
132   GObjectClass *gobject_class;
133   GstElementClass *gstelement_class;
134   GstBaseRTPPayloadClass *gstbasertppayload_class;
135
136   gobject_class = (GObjectClass *) klass;
137   gstelement_class = (GstElementClass *) klass;
138   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
139
140   parent_class = g_type_class_peek_parent (klass);
141
142   gobject_class->set_property = gst_rtp_mp4v_pay_set_property;
143   gobject_class->get_property = gst_rtp_mp4v_pay_get_property;
144
145   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SEND_CONFIG,
146       g_param_spec_boolean ("send-config", "Send Config",
147           "Send the config parameters in RTP packets as well",
148           DEFAULT_SEND_CONFIG, G_PARAM_READWRITE));
149
150   gobject_class->finalize = gst_rtp_mp4v_pay_finalize;
151
152   gstbasertppayload_class->set_caps = gst_rtp_mp4v_pay_setcaps;
153   gstbasertppayload_class->handle_buffer = gst_rtp_mp4v_pay_handle_buffer;
154
155   GST_DEBUG_CATEGORY_INIT (rtpmp4vpay_debug, "rtpmp4vpay", 0,
156       "MP4 video RTP Payloader");
157
158 }
159
160 static void
161 gst_rtp_mp4v_pay_init (GstRtpMP4VPay * rtpmp4vpay)
162 {
163   GstPad *sinkpad;
164
165   rtpmp4vpay->adapter = gst_adapter_new ();
166   rtpmp4vpay->rate = 90000;
167   rtpmp4vpay->profile = 1;
168   rtpmp4vpay->send_config = DEFAULT_SEND_CONFIG;
169
170   rtpmp4vpay->config = NULL;
171
172   sinkpad = GST_BASE_RTP_PAYLOAD_SINKPAD (rtpmp4vpay);
173
174   rtpmp4vpay->old_event_func = sinkpad->eventfunc;
175   gst_pad_set_event_function (sinkpad, gst_rtp_mp4v_pay_event);
176 }
177
178 static void
179 gst_rtp_mp4v_pay_finalize (GObject * object)
180 {
181   GstRtpMP4VPay *rtpmp4vpay;
182
183   rtpmp4vpay = GST_RTP_MP4V_PAY (object);
184
185   if (rtpmp4vpay->config) {
186     gst_buffer_unref (rtpmp4vpay->config);
187     rtpmp4vpay->config = NULL;
188   }
189   g_object_unref (rtpmp4vpay->adapter);
190   rtpmp4vpay->adapter = NULL;
191
192   G_OBJECT_CLASS (parent_class)->finalize (object);
193 }
194
195 static gboolean
196 gst_rtp_mp4v_pay_new_caps (GstRtpMP4VPay * rtpmp4vpay)
197 {
198   gchar *profile, *config;
199   GValue v = { 0 };
200   gboolean res;
201
202   profile = g_strdup_printf ("%d", rtpmp4vpay->profile);
203   g_value_init (&v, GST_TYPE_BUFFER);
204   gst_value_set_buffer (&v, rtpmp4vpay->config);
205   config = gst_value_serialize (&v);
206
207   res = gst_basertppayload_set_outcaps (GST_BASE_RTP_PAYLOAD (rtpmp4vpay),
208       "profile-level-id", G_TYPE_STRING, profile,
209       "config", G_TYPE_STRING, config, NULL);
210
211   g_value_unset (&v);
212
213   g_free (profile);
214   g_free (config);
215
216   return res;
217 }
218
219 static gboolean
220 gst_rtp_mp4v_pay_setcaps (GstBaseRTPPayload * payload, GstCaps * caps)
221 {
222   GstRtpMP4VPay *rtpmp4vpay;
223   GstStructure *structure;
224   const GValue *codec_data;
225   gboolean res;
226
227   rtpmp4vpay = GST_RTP_MP4V_PAY (payload);
228
229   gst_basertppayload_set_options (payload, "video", TRUE, "MP4V-ES",
230       rtpmp4vpay->rate);
231
232   res = TRUE;
233
234   structure = gst_caps_get_structure (caps, 0);
235   codec_data = gst_structure_get_value (structure, "codec_data");
236   if (codec_data) {
237     GST_LOG_OBJECT (rtpmp4vpay, "got codec_data");
238     if (G_VALUE_TYPE (codec_data) == GST_TYPE_BUFFER) {
239       GstBuffer *buffer;
240       guint8 *data;
241       guint size;
242
243       buffer = gst_value_get_buffer (codec_data);
244
245       data = GST_BUFFER_DATA (buffer);
246       size = GST_BUFFER_SIZE (buffer);
247
248       if (size < 5)
249         goto done;
250
251       rtpmp4vpay->profile = data[4];
252       GST_LOG_OBJECT (rtpmp4vpay, "configuring codec_data, profile %d",
253           data[4]);
254
255       if (rtpmp4vpay->config)
256         gst_buffer_unref (rtpmp4vpay->config);
257       rtpmp4vpay->config = gst_buffer_copy (buffer);
258       res = gst_rtp_mp4v_pay_new_caps (rtpmp4vpay);
259     }
260   }
261
262 done:
263   return res;
264 }
265
266 static void
267 gst_rtp_mp4v_pay_empty (GstRtpMP4VPay * rtpmp4vpay)
268 {
269   gst_adapter_clear (rtpmp4vpay->adapter);
270 }
271
272 static GstFlowReturn
273 gst_rtp_mp4v_pay_flush (GstRtpMP4VPay * rtpmp4vpay)
274 {
275   guint avail;
276   GstBuffer *outbuf;
277   GstFlowReturn ret;
278
279   /* the data available in the adapter is either smaller
280    * than the MTU or bigger. In the case it is smaller, the complete
281    * adapter contents can be put in one packet. In the case the
282    * adapter has more than one MTU, we need to split the MP4V data
283    * over multiple packets. */
284   avail = gst_adapter_available (rtpmp4vpay->adapter);
285
286   ret = GST_FLOW_OK;
287
288   while (avail > 0) {
289     guint towrite;
290     guint8 *payload;
291     guint payload_len;
292     guint packet_len;
293
294     /* this will be the total lenght of the packet */
295     packet_len = gst_rtp_buffer_calc_packet_len (avail, 0, 0);
296
297     /* fill one MTU or all available bytes */
298     towrite = MIN (packet_len, GST_BASE_RTP_PAYLOAD_MTU (rtpmp4vpay));
299
300     /* this is the payload length */
301     payload_len = gst_rtp_buffer_calc_payload_len (towrite, 0, 0);
302
303     /* create buffer to hold the payload */
304     outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
305
306     /* copy payload */
307     payload = gst_rtp_buffer_get_payload (outbuf);
308
309     gst_adapter_copy (rtpmp4vpay->adapter, payload, 0, payload_len);
310     gst_adapter_flush (rtpmp4vpay->adapter, payload_len);
311
312     avail -= payload_len;
313
314     gst_rtp_buffer_set_marker (outbuf, avail == 0);
315
316     GST_BUFFER_TIMESTAMP (outbuf) = rtpmp4vpay->first_timestamp;
317
318     ret = gst_basertppayload_push (GST_BASE_RTP_PAYLOAD (rtpmp4vpay), outbuf);
319   }
320
321   return ret;
322 }
323
324 #define VOS_STARTCODE                   0x000001B0
325 #define VOS_ENDCODE                     0x000001B1
326 #define USER_DATA_STARTCODE             0x000001B2
327 #define GOP_STARTCODE                   0x000001B3
328 #define VISUAL_OBJECT_STARTCODE         0x000001B5
329 #define VOP_STARTCODE                   0x000001B6
330
331 static gboolean
332 gst_rtp_mp4v_pay_depay_data (GstRtpMP4VPay * enc, guint8 * data, guint size,
333     gint * strip)
334 {
335   guint32 code;
336   gboolean result;
337
338   *strip = 0;
339
340   if (size < 5)
341     return FALSE;
342
343   code = GST_READ_UINT32_BE (data);
344   GST_DEBUG_OBJECT (enc, "start code 0x%08x", code);
345
346   switch (code) {
347     case VOS_STARTCODE:
348     {
349       gint i;
350       guint8 profile;
351       gboolean newprofile = FALSE;
352       gboolean equal;
353
354       /* profile_and_level_indication */
355       profile = data[4];
356
357       GST_DEBUG_OBJECT (enc, "VOS profile 0x%08x", profile);
358
359       if (profile != enc->profile) {
360         newprofile = TRUE;
361         enc->profile = profile;
362       }
363
364       /* up to the next GOP_STARTCODE or VOP_STARTCODE is
365        * the config information */
366       code = 0xffffffff;
367       for (i = 5; i < size - 4; i++) {
368         code = (code << 8) | data[i];
369         if (code == GOP_STARTCODE || code == VOP_STARTCODE)
370           break;
371       }
372       i -= 3;
373       /* see if config changed */
374       equal = FALSE;
375       if (enc->config) {
376         if (GST_BUFFER_SIZE (enc->config) == i) {
377           equal = memcmp (GST_BUFFER_DATA (enc->config), data, i) == 0;
378         }
379       }
380       /* if config string changed or new profile, make new caps */
381       if (!equal || newprofile) {
382         if (enc->config)
383           gst_buffer_unref (enc->config);
384         enc->config = gst_buffer_new_and_alloc (i);
385         memcpy (GST_BUFFER_DATA (enc->config), data, i);
386         gst_rtp_mp4v_pay_new_caps (enc);
387       }
388       *strip = i;
389       /* we need to flush out the current packet. */
390       result = TRUE;
391       break;
392     }
393     case VOP_STARTCODE:
394       GST_DEBUG_OBJECT (enc, "VOP");
395       /* VOP startcode, we don't have to flush the packet */
396       result = FALSE;
397       break;
398     default:
399       GST_DEBUG_OBJECT (enc, "other startcode");
400       /* all other startcodes need a flush */
401       result = TRUE;
402       break;
403   }
404   return result;
405 }
406
407 /* we expect buffers starting on startcodes. 
408  */
409 static GstFlowReturn
410 gst_rtp_mp4v_pay_handle_buffer (GstBaseRTPPayload * basepayload,
411     GstBuffer * buffer)
412 {
413   GstRtpMP4VPay *rtpmp4vpay;
414   GstFlowReturn ret;
415   guint size, avail;
416   guint packet_len;
417   guint8 *data;
418   gboolean flush;
419   gint strip;
420   GstClockTime timestamp, duration;
421
422   ret = GST_FLOW_OK;
423
424   rtpmp4vpay = GST_RTP_MP4V_PAY (basepayload);
425
426   size = GST_BUFFER_SIZE (buffer);
427   data = GST_BUFFER_DATA (buffer);
428   timestamp = GST_BUFFER_TIMESTAMP (buffer);
429   duration = GST_BUFFER_DURATION (buffer);
430   avail = gst_adapter_available (rtpmp4vpay->adapter);
431
432   if (duration == -1)
433     duration = 0;
434
435   /* empty buffer, take timestamp */
436   if (avail == 0) {
437     rtpmp4vpay->first_timestamp = timestamp;
438     rtpmp4vpay->duration = 0;
439   }
440
441   /* depay incomming data and see if we need to start a new RTP
442    * packet */
443   flush = gst_rtp_mp4v_pay_depay_data (rtpmp4vpay, data, size, &strip);
444   if (strip) {
445     /* strip off config if requested */
446     if (!rtpmp4vpay->send_config) {
447       GstBuffer *subbuf;
448
449       /* strip off header */
450       subbuf = gst_buffer_create_sub (buffer, strip, size - strip);
451       GST_BUFFER_TIMESTAMP (subbuf) = timestamp;
452       gst_buffer_unref (buffer);
453       buffer = subbuf;
454
455       size = GST_BUFFER_SIZE (buffer);
456       data = GST_BUFFER_DATA (buffer);
457     }
458   }
459
460   /* if we need to flush, do so now */
461   if (flush) {
462     ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
463     rtpmp4vpay->first_timestamp = timestamp;
464     rtpmp4vpay->duration = 0;
465     avail = 0;
466   }
467
468   /* get packet length of data and see if we exceeded MTU. */
469   packet_len = gst_rtp_buffer_calc_packet_len (avail + size, 0, 0);
470
471   if (gst_basertppayload_is_filled (basepayload,
472           packet_len, rtpmp4vpay->duration + duration)) {
473     ret = gst_rtp_mp4v_pay_flush (rtpmp4vpay);
474     rtpmp4vpay->first_timestamp = timestamp;
475     rtpmp4vpay->duration = 0;
476   }
477
478   /* push new data */
479   gst_adapter_push (rtpmp4vpay->adapter, buffer);
480
481   rtpmp4vpay->duration += duration;
482
483   return ret;
484 }
485
486 static gboolean
487 gst_rtp_mp4v_pay_event (GstPad * pad, GstEvent * event)
488 {
489   GstRtpMP4VPay *rtpmp4vpay;
490   gboolean ret;
491
492   rtpmp4vpay = GST_RTP_MP4V_PAY (gst_pad_get_parent (pad));
493
494   GST_DEBUG ("Got event: %s", GST_EVENT_TYPE_NAME (event));
495
496   switch (GST_EVENT_TYPE (event)) {
497     case GST_EVENT_NEWSEGMENT:
498     case GST_EVENT_EOS:
499       /* This flush call makes sure that the last buffer is always pushed
500        * to the base payloader */
501       gst_rtp_mp4v_pay_flush (rtpmp4vpay);
502       break;
503     case GST_EVENT_FLUSH_STOP:
504       gst_rtp_mp4v_pay_empty (rtpmp4vpay);
505       break;
506     default:
507       break;
508   }
509
510   ret = rtpmp4vpay->old_event_func (pad, event);
511
512   g_object_unref (rtpmp4vpay);
513
514   return ret;
515 }
516
517 static void
518 gst_rtp_mp4v_pay_set_property (GObject * object, guint prop_id,
519     const GValue * value, GParamSpec * pspec)
520 {
521   GstRtpMP4VPay *rtpmp4vpay;
522
523   rtpmp4vpay = GST_RTP_MP4V_PAY (object);
524
525   switch (prop_id) {
526     case ARG_SEND_CONFIG:
527       rtpmp4vpay->send_config = g_value_get_boolean (value);
528       break;
529     default:
530       break;
531   }
532 }
533
534 static void
535 gst_rtp_mp4v_pay_get_property (GObject * object, guint prop_id,
536     GValue * value, GParamSpec * pspec)
537 {
538   GstRtpMP4VPay *rtpmp4vpay;
539
540   rtpmp4vpay = GST_RTP_MP4V_PAY (object);
541
542   switch (prop_id) {
543     case ARG_SEND_CONFIG:
544       g_value_set_boolean (value, rtpmp4vpay->send_config);
545       break;
546     default:
547       break;
548   }
549 }
550
551 gboolean
552 gst_rtp_mp4v_pay_plugin_init (GstPlugin * plugin)
553 {
554   return gst_element_register (plugin, "rtpmp4vpay",
555       GST_RANK_NONE, GST_TYPE_RTP_MP4V_PAY);
556 }