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