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