f6294195acf729795316b5fd0321921a691bde9d
[platform/upstream/gst-plugins-good.git] / gst / rtp / gstrtpj2kdepay.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 <gst/rtp/gstrtpbuffer.h>
25 #include <gst/video/video.h>
26
27 #include <string.h>
28 #include "gstrtpj2kdepay.h"
29 #include "gstrtputils.h"
30
31 GST_DEBUG_CATEGORY_STATIC (rtpj2kdepay_debug);
32 #define GST_CAT_DEFAULT (rtpj2kdepay_debug)
33
34 static GstStaticPadTemplate gst_rtp_j2k_depay_src_template =
35 GST_STATIC_PAD_TEMPLATE ("src",
36     GST_PAD_SRC,
37     GST_PAD_ALWAYS,
38     GST_STATIC_CAPS ("image/x-jpc")
39     );
40
41 static GstStaticPadTemplate gst_rtp_j2k_depay_sink_template =
42 GST_STATIC_PAD_TEMPLATE ("sink",
43     GST_PAD_SINK,
44     GST_PAD_ALWAYS,
45     GST_STATIC_CAPS ("application/x-rtp, "
46         "media = (string) \"video\", "
47         "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG2000\"")
48     );
49
50 typedef enum
51 {
52   J2K_MARKER = 0xFF,
53   J2K_MARKER_SOC = 0x4F,
54   J2K_MARKER_SOT = 0x90,
55   J2K_MARKER_SOP = 0x91,
56   J2K_MARKER_SOD = 0x93,
57   J2K_MARKER_EOC = 0xD9
58 } RtpJ2KMarker;
59
60 enum
61 {
62   PROP_0,
63   PROP_LAST
64 };
65
66 #define gst_rtp_j2k_depay_parent_class parent_class
67 G_DEFINE_TYPE (GstRtpJ2KDepay, gst_rtp_j2k_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
68
69 static void gst_rtp_j2k_depay_finalize (GObject * object);
70
71 static void gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
72     const GValue * value, GParamSpec * pspec);
73 static void gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
74     GValue * value, GParamSpec * pspec);
75
76 static GstStateChangeReturn
77 gst_rtp_j2k_depay_change_state (GstElement * element,
78     GstStateChange transition);
79
80 static gboolean gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload,
81     GstCaps * caps);
82 static GstBuffer *gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload,
83     GstRTPBuffer * rtp);
84
85 static void
86 gst_rtp_j2k_depay_class_init (GstRtpJ2KDepayClass * klass)
87 {
88   GObjectClass *gobject_class;
89   GstElementClass *gstelement_class;
90   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
91
92   gobject_class = (GObjectClass *) klass;
93   gstelement_class = (GstElementClass *) klass;
94   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
95
96   gobject_class->finalize = gst_rtp_j2k_depay_finalize;
97
98   gobject_class->set_property = gst_rtp_j2k_depay_set_property;
99   gobject_class->get_property = gst_rtp_j2k_depay_get_property;
100
101   gst_element_class_add_static_pad_template (gstelement_class,
102       &gst_rtp_j2k_depay_src_template);
103   gst_element_class_add_static_pad_template (gstelement_class,
104       &gst_rtp_j2k_depay_sink_template);
105
106   gst_element_class_set_static_metadata (gstelement_class,
107       "RTP JPEG 2000 depayloader", "Codec/Depayloader/Network/RTP",
108       "Extracts JPEG 2000 video from RTP packets (RFC 5371)",
109       "Wim Taymans <wim.taymans@gmail.com>");
110
111   gstelement_class->change_state = gst_rtp_j2k_depay_change_state;
112
113   gstrtpbasedepayload_class->set_caps = gst_rtp_j2k_depay_setcaps;
114   gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_j2k_depay_process;
115
116   GST_DEBUG_CATEGORY_INIT (rtpj2kdepay_debug, "rtpj2kdepay", 0,
117       "J2K Video RTP Depayloader");
118 }
119
120 static void
121 gst_rtp_j2k_depay_init (GstRtpJ2KDepay * rtpj2kdepay)
122 {
123   rtpj2kdepay->pu_adapter = gst_adapter_new ();
124   rtpj2kdepay->t_adapter = gst_adapter_new ();
125   rtpj2kdepay->f_adapter = gst_adapter_new ();
126 }
127
128 static void
129 store_mheader (GstRtpJ2KDepay * rtpj2kdepay, guint idx, GstBuffer * buf)
130 {
131   GstBuffer *old;
132
133   GST_DEBUG_OBJECT (rtpj2kdepay, "storing main header %p at index %u", buf,
134       idx);
135   if ((old = rtpj2kdepay->MH[idx]))
136     gst_buffer_unref (old);
137   rtpj2kdepay->MH[idx] = buf;
138 }
139
140 static void
141 clear_mheaders (GstRtpJ2KDepay * rtpj2kdepay)
142 {
143   guint i;
144
145   for (i = 0; i < 8; i++)
146     store_mheader (rtpj2kdepay, i, NULL);
147 }
148
149 static void
150 gst_rtp_j2k_depay_reset (GstRtpJ2KDepay * rtpj2kdepay)
151 {
152   clear_mheaders (rtpj2kdepay);
153   gst_adapter_clear (rtpj2kdepay->pu_adapter);
154   gst_adapter_clear (rtpj2kdepay->t_adapter);
155   gst_adapter_clear (rtpj2kdepay->f_adapter);
156   rtpj2kdepay->next_frag = 0;
157 }
158
159 static void
160 gst_rtp_j2k_depay_finalize (GObject * object)
161 {
162   GstRtpJ2KDepay *rtpj2kdepay;
163
164   rtpj2kdepay = GST_RTP_J2K_DEPAY (object);
165
166   clear_mheaders (rtpj2kdepay);
167
168   g_object_unref (rtpj2kdepay->pu_adapter);
169   g_object_unref (rtpj2kdepay->t_adapter);
170   g_object_unref (rtpj2kdepay->f_adapter);
171
172   G_OBJECT_CLASS (parent_class)->finalize (object);
173 }
174
175 static gboolean
176 gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
177 {
178   GstStructure *structure;
179   gint clock_rate;
180   GstCaps *outcaps;
181   gboolean res;
182
183   structure = gst_caps_get_structure (caps, 0);
184
185   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
186     clock_rate = 90000;
187   depayload->clock_rate = clock_rate;
188
189   outcaps =
190       gst_caps_new_simple ("image/x-jpc", "framerate", GST_TYPE_FRACTION, 0, 1,
191       "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, "sYUV", NULL);
192   res = gst_pad_set_caps (depayload->srcpad, outcaps);
193   gst_caps_unref (outcaps);
194
195   return res;
196 }
197
198 static void
199 gst_rtp_j2k_depay_clear_pu (GstRtpJ2KDepay * rtpj2kdepay)
200 {
201   gst_adapter_clear (rtpj2kdepay->pu_adapter);
202   rtpj2kdepay->have_sync = FALSE;
203 }
204
205 static GstFlowReturn
206 gst_rtp_j2k_depay_flush_pu (GstRTPBaseDepayload * depayload)
207 {
208   GstRtpJ2KDepay *rtpj2kdepay;
209   GstBuffer *mheader;
210   guint avail, MHF, mh_id;
211
212   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
213
214   /* take all available buffers */
215   avail = gst_adapter_available (rtpj2kdepay->pu_adapter);
216   if (avail == 0)
217     goto done;
218
219   MHF = rtpj2kdepay->pu_MHF;
220   mh_id = rtpj2kdepay->last_mh_id;
221
222   GST_DEBUG_OBJECT (rtpj2kdepay, "flushing PU of size %u", avail);
223
224   if (MHF == 0) {
225     GList *packets, *walk;
226
227     packets = gst_adapter_take_list (rtpj2kdepay->pu_adapter, avail);
228     /* append packets */
229     for (walk = packets; walk; walk = g_list_next (walk)) {
230       GstBuffer *buf = GST_BUFFER_CAST (walk->data);
231       GST_DEBUG_OBJECT (rtpj2kdepay,
232           "append pu packet of size %" G_GSIZE_FORMAT,
233           gst_buffer_get_size (buf));
234       gst_adapter_push (rtpj2kdepay->t_adapter, buf);
235     }
236     g_list_free (packets);
237   } else {
238     /* we have a header */
239     GST_DEBUG_OBJECT (rtpj2kdepay, "keeping header %u", mh_id);
240     /* we managed to see the start and end of the header, take all from
241      * adapter and keep in header  */
242     mheader = gst_adapter_take_buffer (rtpj2kdepay->pu_adapter, avail);
243
244     store_mheader (rtpj2kdepay, mh_id, mheader);
245   }
246
247 done:
248   rtpj2kdepay->have_sync = FALSE;
249
250   return GST_FLOW_OK;
251 }
252
253 static GstFlowReturn
254 gst_rtp_j2k_depay_flush_tile (GstRTPBaseDepayload * depayload)
255 {
256   GstRtpJ2KDepay *rtpj2kdepay;
257   guint avail, mh_id;
258   GList *packets, *walk;
259   guint8 end[2];
260   GstFlowReturn ret = GST_FLOW_OK;
261   GstMapInfo map;
262   GstBuffer *buf;
263
264   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
265
266   /* flush pending PU */
267   gst_rtp_j2k_depay_flush_pu (depayload);
268
269   /* take all available buffers */
270   avail = gst_adapter_available (rtpj2kdepay->t_adapter);
271   if (avail == 0)
272     goto done;
273
274   mh_id = rtpj2kdepay->last_mh_id;
275
276   GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail);
277
278   if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) {
279     GstBuffer *mheader;
280
281     /* we need a header now */
282     if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL)
283       goto waiting_header;
284
285     /* push header in the adapter */
286     GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id);
287     gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader));
288   }
289
290   /* check for last bytes */
291   gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2);
292
293   /* now append the tile packets to the frame */
294   packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail);
295   for (walk = packets; walk; walk = g_list_next (walk)) {
296     buf = GST_BUFFER_CAST (walk->data);
297
298     if (walk == packets) {
299       /* first buffer should contain the SOT */
300       gst_buffer_map (buf, &map, GST_MAP_READ);
301
302       if (map.size < 12)
303         goto invalid_tile;
304
305       if (map.data[0] == 0xff && map.data[1] == J2K_MARKER_SOT) {
306         guint Psot, nPsot;
307
308         if (end[0] == 0xff && end[1] == J2K_MARKER_EOC)
309           nPsot = avail - 2;
310         else
311           nPsot = avail;
312
313         Psot = GST_READ_UINT32_BE (&map.data[6]);
314         if (Psot != nPsot && Psot != 0) {
315           /* Psot must match the size of the tile */
316           GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot);
317           gst_buffer_unmap (buf, &map);
318
319           buf = gst_buffer_make_writable (buf);
320
321           gst_buffer_map (buf, &map, GST_MAP_WRITE);
322           GST_WRITE_UINT32_BE (&map.data[6], nPsot);
323         }
324       }
325       gst_buffer_unmap (buf, &map);
326     }
327
328     GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %" G_GSIZE_FORMAT,
329         gst_buffer_get_size (buf));
330     gst_adapter_push (rtpj2kdepay->f_adapter, buf);
331   }
332   g_list_free (packets);
333
334 done:
335   rtpj2kdepay->last_tile = -1;
336
337   return ret;
338
339   /* errors */
340 waiting_header:
341   {
342     GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id);
343     gst_adapter_clear (rtpj2kdepay->t_adapter);
344     rtpj2kdepay->last_tile = -1;
345     return ret;
346   }
347 invalid_tile:
348   {
349     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL));
350     gst_buffer_unmap (buf, &map);
351     gst_adapter_clear (rtpj2kdepay->t_adapter);
352     rtpj2kdepay->last_tile = -1;
353     return ret;
354   }
355 }
356
357 static GstFlowReturn
358 gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload)
359 {
360   GstRtpJ2KDepay *rtpj2kdepay;
361   guint8 end[2];
362   guint avail;
363
364   GstFlowReturn ret = GST_FLOW_OK;
365
366   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
367
368   /* flush pending tile */
369   gst_rtp_j2k_depay_flush_tile (depayload);
370
371   /* last buffer take all data out of the adapter */
372   avail = gst_adapter_available (rtpj2kdepay->f_adapter);
373   if (avail == 0)
374     goto done;
375
376   if (avail > 2) {
377     GstBuffer *outbuf;
378
379     /* take the last bytes of the JPEG 2000 data to see if there is an EOC
380      * marker */
381     gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);
382
383     if (end[0] != 0xff && end[1] != 0xd9) {
384       end[0] = 0xff;
385       end[1] = 0xd9;
386
387       GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");
388
389       /* no EOI marker, add one */
390       outbuf = gst_buffer_new_and_alloc (2);
391       gst_buffer_fill (outbuf, 0, end, 2);
392
393       gst_adapter_push (rtpj2kdepay->f_adapter, outbuf);
394       avail += 2;
395     }
396
397     GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail);
398     outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail);
399     gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload),
400         outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
401     ret = gst_rtp_base_depayload_push (depayload, outbuf);
402   } else {
403     GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
404     gst_adapter_clear (rtpj2kdepay->f_adapter);
405   }
406
407   /* we accept any mh_id now */
408   rtpj2kdepay->last_mh_id = -1;
409
410   /* reset state */
411   rtpj2kdepay->next_frag = 0;
412   rtpj2kdepay->have_sync = FALSE;
413
414 done:
415   /* we can't keep headers with mh_id of 0 */
416   store_mheader (rtpj2kdepay, 0, NULL);
417
418   return ret;
419 }
420
421 static GstBuffer *
422 gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
423 {
424   GstRtpJ2KDepay *rtpj2kdepay;
425   guint8 *payload;
426   guint MHF, mh_id, frag_offset, tile, payload_len, j2klen;
427   gint gap;
428   guint32 rtptime;
429
430   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
431
432   payload = gst_rtp_buffer_get_payload (rtp);
433   payload_len = gst_rtp_buffer_get_payload_len (rtp);
434
435   /* we need at least a header */
436   if (payload_len < 8)
437     goto empty_packet;
438
439   rtptime = gst_rtp_buffer_get_timestamp (rtp);
440
441   /* new timestamp marks new frame */
442   if (rtpj2kdepay->last_rtptime != rtptime) {
443     rtpj2kdepay->last_rtptime = rtptime;
444     /* flush pending frame */
445     gst_rtp_j2k_depay_flush_frame (depayload);
446   }
447
448   /*
449    *  0                   1                   2                   3
450    *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
451    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452    * |tp |MHF|mh_id|T|     priority  |           tile number         |
453    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454    * |reserved       |             fragment offset                   |
455    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
456    */
457   MHF = (payload[0] & 0x30) >> 4;
458   mh_id = (payload[0] & 0xe) >> 1;
459
460   if (rtpj2kdepay->last_mh_id == -1)
461     rtpj2kdepay->last_mh_id = mh_id;
462   else if (rtpj2kdepay->last_mh_id != mh_id)
463     goto wrong_mh_id;
464
465   tile = (payload[2] << 8) | payload[3];
466   frag_offset = (payload[5] << 16) | (payload[6] << 8) | payload[7];
467   j2klen = payload_len - 8;
468
469   GST_DEBUG_OBJECT (rtpj2kdepay, "MHF %u, tile %u, frag %u, expected %u", MHF,
470       tile, frag_offset, rtpj2kdepay->next_frag);
471
472   /* calculate the gap between expected frag */
473   gap = frag_offset - rtpj2kdepay->next_frag;
474   /* calculate next frag */
475   rtpj2kdepay->next_frag = frag_offset + j2klen;
476
477   if (gap != 0) {
478     GST_DEBUG_OBJECT (rtpj2kdepay, "discont of %d, clear PU", gap);
479     /* discont, clear pu adapter and resync */
480     gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
481   }
482
483   /* check for sync code */
484   if (j2klen > 2 && payload[8] == 0xff) {
485     guint marker = payload[9];
486
487     /* packets must start with SOC, SOT or SOP */
488     switch (marker) {
489       case J2K_MARKER_SOC:
490         GST_DEBUG_OBJECT (rtpj2kdepay, "found SOC packet");
491         /* flush the previous frame, should have happened when the timestamp
492          * changed above. */
493         gst_rtp_j2k_depay_flush_frame (depayload);
494         rtpj2kdepay->have_sync = TRUE;
495         break;
496       case J2K_MARKER_SOT:
497         /* flush the previous tile */
498         gst_rtp_j2k_depay_flush_tile (depayload);
499         GST_DEBUG_OBJECT (rtpj2kdepay, "found SOT packet");
500         rtpj2kdepay->have_sync = TRUE;
501         /* we sync on the tile now */
502         rtpj2kdepay->last_tile = tile;
503         break;
504       case J2K_MARKER_SOP:
505         GST_DEBUG_OBJECT (rtpj2kdepay, "found SOP packet");
506         /* flush the previous PU */
507         gst_rtp_j2k_depay_flush_pu (depayload);
508         if (rtpj2kdepay->last_tile != tile) {
509           /* wrong tile, we lose sync and we need a new SOT or SOC to regain
510            * sync. First flush out the previous tile if we have one. */
511           if (rtpj2kdepay->last_tile != -1)
512             gst_rtp_j2k_depay_flush_tile (depayload);
513           /* now we have no more valid tile and no sync */
514           rtpj2kdepay->last_tile = -1;
515           rtpj2kdepay->have_sync = FALSE;
516         } else {
517           rtpj2kdepay->have_sync = TRUE;
518         }
519         break;
520       default:
521         GST_DEBUG_OBJECT (rtpj2kdepay, "no sync packet 0x%02d", marker);
522         break;
523     }
524   }
525
526   if (rtpj2kdepay->have_sync) {
527     GstBuffer *pu_frag;
528
529     if (gst_adapter_available (rtpj2kdepay->pu_adapter) == 0) {
530       /* first part of pu, record state */
531       GST_DEBUG_OBJECT (rtpj2kdepay, "first PU");
532       rtpj2kdepay->pu_MHF = MHF;
533     }
534     /* and push in pu adapter */
535     GST_DEBUG_OBJECT (rtpj2kdepay, "push pu of size %u in adapter", j2klen);
536     pu_frag = gst_rtp_buffer_get_payload_subbuffer (rtp, 8, -1);
537     gst_adapter_push (rtpj2kdepay->pu_adapter, pu_frag);
538
539     if (MHF & 2) {
540       /* last part of main header received, we can flush it */
541       GST_DEBUG_OBJECT (rtpj2kdepay, "header end, flush pu");
542       gst_rtp_j2k_depay_flush_pu (depayload);
543     }
544   } else {
545     GST_DEBUG_OBJECT (rtpj2kdepay, "discard packet, no sync");
546   }
547
548   /* marker bit finishes the frame */
549   if (gst_rtp_buffer_get_marker (rtp)) {
550     GST_DEBUG_OBJECT (rtpj2kdepay, "marker set, last buffer");
551     /* then flush frame */
552     gst_rtp_j2k_depay_flush_frame (depayload);
553   }
554
555   return NULL;
556
557   /* ERRORS */
558 empty_packet:
559   {
560     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
561         ("Empty Payload."), (NULL));
562     return NULL;
563   }
564 wrong_mh_id:
565   {
566     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
567         ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id),
568         (NULL));
569     gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
570     return NULL;
571   }
572 }
573
574 static void
575 gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
576     const GValue * value, GParamSpec * pspec)
577 {
578   switch (prop_id) {
579     default:
580       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
581       break;
582   }
583 }
584
585 static void
586 gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
587     GValue * value, GParamSpec * pspec)
588 {
589   switch (prop_id) {
590     default:
591       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
592       break;
593   }
594 }
595
596 static GstStateChangeReturn
597 gst_rtp_j2k_depay_change_state (GstElement * element, GstStateChange transition)
598 {
599   GstRtpJ2KDepay *rtpj2kdepay;
600   GstStateChangeReturn ret;
601
602   rtpj2kdepay = GST_RTP_J2K_DEPAY (element);
603
604   switch (transition) {
605     case GST_STATE_CHANGE_NULL_TO_READY:
606       break;
607     case GST_STATE_CHANGE_READY_TO_PAUSED:
608       gst_rtp_j2k_depay_reset (rtpj2kdepay);
609       break;
610     default:
611       break;
612   }
613
614   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
615
616   switch (transition) {
617     case GST_STATE_CHANGE_PAUSED_TO_READY:
618       gst_rtp_j2k_depay_reset (rtpj2kdepay);
619       break;
620     case GST_STATE_CHANGE_READY_TO_NULL:
621       break;
622     default:
623       break;
624   }
625   return ret;
626 }
627
628 gboolean
629 gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin)
630 {
631   return gst_element_register (plugin, "rtpj2kdepay",
632       GST_RANK_SECONDARY, GST_TYPE_RTP_J2K_DEPAY);
633 }