rtpj2k: update documentation
[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
21  /**
22  * SECTION:element-rtpj2kdepay
23  *
24  * Depayload an RTP-payloaded JPEG 2000 image into RTP packets according to RFC 5371
25  * and RFC 5372.
26  * For detailed information see: https://datatracker.ietf.org/doc/rfc5371/
27  * and https://datatracker.ietf.org/doc/rfc5372/
28  */
29
30
31 #ifdef HAVE_CONFIG_H
32 #  include "config.h"
33 #endif
34
35 #include <gst/rtp/gstrtpbuffer.h>
36 #include <gst/video/video.h>
37
38 #include <string.h>
39 #include "gstrtpj2kdepay.h"
40 #include "gstrtputils.h"
41
42 GST_DEBUG_CATEGORY_STATIC (rtpj2kdepay_debug);
43 #define GST_CAT_DEFAULT (rtpj2kdepay_debug)
44
45 static GstStaticPadTemplate gst_rtp_j2k_depay_src_template =
46 GST_STATIC_PAD_TEMPLATE ("src",
47     GST_PAD_SRC,
48     GST_PAD_ALWAYS,
49     GST_STATIC_CAPS ("image/x-jpc")
50     );
51
52 static GstStaticPadTemplate gst_rtp_j2k_depay_sink_template =
53 GST_STATIC_PAD_TEMPLATE ("sink",
54     GST_PAD_SINK,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("application/x-rtp, "
57         "media = (string) \"video\", "
58         "clock-rate = (int) 90000, " "encoding-name = (string) \"JPEG2000\"")
59     );
60
61 typedef enum
62 {
63   J2K_MARKER = 0xFF,
64   J2K_MARKER_SOC = 0x4F,
65   J2K_MARKER_SOT = 0x90,
66   J2K_MARKER_SOP = 0x91,
67   J2K_MARKER_SOD = 0x93,
68   J2K_MARKER_EOC = 0xD9
69 } RtpJ2KMarker;
70
71 enum
72 {
73   PROP_0,
74   PROP_LAST
75 };
76
77 #define gst_rtp_j2k_depay_parent_class parent_class
78 G_DEFINE_TYPE (GstRtpJ2KDepay, gst_rtp_j2k_depay, GST_TYPE_RTP_BASE_DEPAYLOAD);
79
80 static void gst_rtp_j2k_depay_finalize (GObject * object);
81
82 static void gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
83     const GValue * value, GParamSpec * pspec);
84 static void gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
85     GValue * value, GParamSpec * pspec);
86
87 static GstStateChangeReturn
88 gst_rtp_j2k_depay_change_state (GstElement * element,
89     GstStateChange transition);
90
91 static gboolean gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload,
92     GstCaps * caps);
93 static GstBuffer *gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload,
94     GstRTPBuffer * rtp);
95
96 static void
97 gst_rtp_j2k_depay_class_init (GstRtpJ2KDepayClass * klass)
98 {
99   GObjectClass *gobject_class;
100   GstElementClass *gstelement_class;
101   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
102
103   gobject_class = (GObjectClass *) klass;
104   gstelement_class = (GstElementClass *) klass;
105   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
106
107   gobject_class->finalize = gst_rtp_j2k_depay_finalize;
108
109   gobject_class->set_property = gst_rtp_j2k_depay_set_property;
110   gobject_class->get_property = gst_rtp_j2k_depay_get_property;
111
112   gst_element_class_add_static_pad_template (gstelement_class,
113       &gst_rtp_j2k_depay_src_template);
114   gst_element_class_add_static_pad_template (gstelement_class,
115       &gst_rtp_j2k_depay_sink_template);
116
117   gst_element_class_set_static_metadata (gstelement_class,
118       "RTP JPEG 2000 depayloader", "Codec/Depayloader/Network/RTP",
119       "Extracts JPEG 2000 video from RTP packets (RFC 5371)",
120       "Wim Taymans <wim.taymans@gmail.com>");
121
122   gstelement_class->change_state = gst_rtp_j2k_depay_change_state;
123
124   gstrtpbasedepayload_class->set_caps = gst_rtp_j2k_depay_setcaps;
125   gstrtpbasedepayload_class->process_rtp_packet = gst_rtp_j2k_depay_process;
126
127   GST_DEBUG_CATEGORY_INIT (rtpj2kdepay_debug, "rtpj2kdepay", 0,
128       "J2K Video RTP Depayloader");
129 }
130
131 static void
132 gst_rtp_j2k_depay_init (GstRtpJ2KDepay * rtpj2kdepay)
133 {
134   rtpj2kdepay->pu_adapter = gst_adapter_new ();
135   rtpj2kdepay->t_adapter = gst_adapter_new ();
136   rtpj2kdepay->f_adapter = gst_adapter_new ();
137 }
138
139 static void
140 store_mheader (GstRtpJ2KDepay * rtpj2kdepay, guint idx, GstBuffer * buf)
141 {
142   GstBuffer *old;
143
144   GST_DEBUG_OBJECT (rtpj2kdepay, "storing main header %p at index %u", buf,
145       idx);
146   if ((old = rtpj2kdepay->MH[idx]))
147     gst_buffer_unref (old);
148   rtpj2kdepay->MH[idx] = buf;
149 }
150
151 static void
152 clear_mheaders (GstRtpJ2KDepay * rtpj2kdepay)
153 {
154   guint i;
155
156   for (i = 0; i < 8; i++)
157     store_mheader (rtpj2kdepay, i, NULL);
158 }
159
160 static void
161 gst_rtp_j2k_depay_reset (GstRtpJ2KDepay * rtpj2kdepay)
162 {
163   clear_mheaders (rtpj2kdepay);
164   gst_adapter_clear (rtpj2kdepay->pu_adapter);
165   gst_adapter_clear (rtpj2kdepay->t_adapter);
166   gst_adapter_clear (rtpj2kdepay->f_adapter);
167   rtpj2kdepay->next_frag = 0;
168 }
169
170 static void
171 gst_rtp_j2k_depay_finalize (GObject * object)
172 {
173   GstRtpJ2KDepay *rtpj2kdepay;
174
175   rtpj2kdepay = GST_RTP_J2K_DEPAY (object);
176
177   clear_mheaders (rtpj2kdepay);
178
179   g_object_unref (rtpj2kdepay->pu_adapter);
180   g_object_unref (rtpj2kdepay->t_adapter);
181   g_object_unref (rtpj2kdepay->f_adapter);
182
183   G_OBJECT_CLASS (parent_class)->finalize (object);
184 }
185
186 static gboolean
187 gst_rtp_j2k_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
188 {
189   GstStructure *structure;
190   gint clock_rate;
191   GstCaps *outcaps;
192   gboolean res;
193
194   structure = gst_caps_get_structure (caps, 0);
195
196   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
197     clock_rate = 90000;
198   depayload->clock_rate = clock_rate;
199
200   outcaps =
201       gst_caps_new_simple ("image/x-jpc", "framerate", GST_TYPE_FRACTION, 0, 1,
202       "fields", G_TYPE_INT, 1, "colorspace", G_TYPE_STRING, "sYUV", NULL);
203   res = gst_pad_set_caps (depayload->srcpad, outcaps);
204   gst_caps_unref (outcaps);
205
206   return res;
207 }
208
209 static void
210 gst_rtp_j2k_depay_clear_pu (GstRtpJ2KDepay * rtpj2kdepay)
211 {
212   gst_adapter_clear (rtpj2kdepay->pu_adapter);
213   rtpj2kdepay->have_sync = FALSE;
214 }
215
216 static GstFlowReturn
217 gst_rtp_j2k_depay_flush_pu (GstRTPBaseDepayload * depayload)
218 {
219   GstRtpJ2KDepay *rtpj2kdepay;
220   GstBuffer *mheader;
221   guint avail, MHF, mh_id;
222
223   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
224
225   /* take all available buffers */
226   avail = gst_adapter_available (rtpj2kdepay->pu_adapter);
227   if (avail == 0)
228     goto done;
229
230   MHF = rtpj2kdepay->pu_MHF;
231   mh_id = rtpj2kdepay->last_mh_id;
232
233   GST_DEBUG_OBJECT (rtpj2kdepay, "flushing PU of size %u", avail);
234
235   if (MHF == 0) {
236     GList *packets, *walk;
237
238     packets = gst_adapter_take_list (rtpj2kdepay->pu_adapter, avail);
239     /* append packets */
240     for (walk = packets; walk; walk = g_list_next (walk)) {
241       GstBuffer *buf = GST_BUFFER_CAST (walk->data);
242       GST_DEBUG_OBJECT (rtpj2kdepay,
243           "append pu packet of size %" G_GSIZE_FORMAT,
244           gst_buffer_get_size (buf));
245       gst_adapter_push (rtpj2kdepay->t_adapter, buf);
246     }
247     g_list_free (packets);
248   } else {
249     /* we have a header */
250     GST_DEBUG_OBJECT (rtpj2kdepay, "keeping header %u", mh_id);
251     /* we managed to see the start and end of the header, take all from
252      * adapter and keep in header  */
253     mheader = gst_adapter_take_buffer (rtpj2kdepay->pu_adapter, avail);
254
255     store_mheader (rtpj2kdepay, mh_id, mheader);
256   }
257
258 done:
259   rtpj2kdepay->have_sync = FALSE;
260
261   return GST_FLOW_OK;
262 }
263
264 static GstFlowReturn
265 gst_rtp_j2k_depay_flush_tile (GstRTPBaseDepayload * depayload)
266 {
267   GstRtpJ2KDepay *rtpj2kdepay;
268   guint avail, mh_id;
269   GList *packets, *walk;
270   guint8 end[2];
271   GstFlowReturn ret = GST_FLOW_OK;
272   GstMapInfo map;
273   GstBuffer *buf;
274
275   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
276
277   /* flush pending PU */
278   gst_rtp_j2k_depay_flush_pu (depayload);
279
280   /* take all available buffers */
281   avail = gst_adapter_available (rtpj2kdepay->t_adapter);
282   if (avail == 0)
283     goto done;
284
285   mh_id = rtpj2kdepay->last_mh_id;
286
287   GST_DEBUG_OBJECT (rtpj2kdepay, "flushing tile of size %u", avail);
288
289   if (gst_adapter_available (rtpj2kdepay->f_adapter) == 0) {
290     GstBuffer *mheader;
291
292     /* we need a header now */
293     if ((mheader = rtpj2kdepay->MH[mh_id]) == NULL)
294       goto waiting_header;
295
296     /* push header in the adapter */
297     GST_DEBUG_OBJECT (rtpj2kdepay, "pushing header %u", mh_id);
298     gst_adapter_push (rtpj2kdepay->f_adapter, gst_buffer_ref (mheader));
299   }
300
301   /* check for last bytes */
302   gst_adapter_copy (rtpj2kdepay->t_adapter, end, avail - 2, 2);
303
304   /* now append the tile packets to the frame */
305   packets = gst_adapter_take_list (rtpj2kdepay->t_adapter, avail);
306   for (walk = packets; walk; walk = g_list_next (walk)) {
307     buf = GST_BUFFER_CAST (walk->data);
308
309     if (walk == packets) {
310       /* first buffer should contain the SOT */
311       gst_buffer_map (buf, &map, GST_MAP_READ);
312
313       if (map.size < 12)
314         goto invalid_tile;
315
316       if (map.data[0] == 0xff && map.data[1] == J2K_MARKER_SOT) {
317         guint Psot, nPsot;
318
319         if (end[0] == 0xff && end[1] == J2K_MARKER_EOC)
320           nPsot = avail - 2;
321         else
322           nPsot = avail;
323
324         Psot = GST_READ_UINT32_BE (&map.data[6]);
325         if (Psot != nPsot && Psot != 0) {
326           /* Psot must match the size of the tile */
327           GST_DEBUG_OBJECT (rtpj2kdepay, "set Psot from %u to %u", Psot, nPsot);
328           gst_buffer_unmap (buf, &map);
329
330           buf = gst_buffer_make_writable (buf);
331
332           gst_buffer_map (buf, &map, GST_MAP_WRITE);
333           GST_WRITE_UINT32_BE (&map.data[6], nPsot);
334         }
335       }
336       gst_buffer_unmap (buf, &map);
337     }
338
339     GST_DEBUG_OBJECT (rtpj2kdepay, "append pu packet of size %" G_GSIZE_FORMAT,
340         gst_buffer_get_size (buf));
341     gst_adapter_push (rtpj2kdepay->f_adapter, buf);
342   }
343   g_list_free (packets);
344
345 done:
346   rtpj2kdepay->last_tile = -1;
347
348   return ret;
349
350   /* errors */
351 waiting_header:
352   {
353     GST_DEBUG_OBJECT (rtpj2kdepay, "waiting for header %u", mh_id);
354     gst_adapter_clear (rtpj2kdepay->t_adapter);
355     rtpj2kdepay->last_tile = -1;
356     return ret;
357   }
358 invalid_tile:
359   {
360     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE, ("Invalid tile"), (NULL));
361     gst_buffer_unmap (buf, &map);
362     gst_adapter_clear (rtpj2kdepay->t_adapter);
363     rtpj2kdepay->last_tile = -1;
364     return ret;
365   }
366 }
367
368 static GstFlowReturn
369 gst_rtp_j2k_depay_flush_frame (GstRTPBaseDepayload * depayload)
370 {
371   GstRtpJ2KDepay *rtpj2kdepay;
372   guint8 end[2];
373   guint avail;
374
375   GstFlowReturn ret = GST_FLOW_OK;
376
377   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
378
379   /* flush pending tile */
380   gst_rtp_j2k_depay_flush_tile (depayload);
381
382   /* last buffer take all data out of the adapter */
383   avail = gst_adapter_available (rtpj2kdepay->f_adapter);
384   if (avail == 0)
385     goto done;
386
387   if (avail > 2) {
388     GstBuffer *outbuf;
389
390     /* take the last bytes of the JPEG 2000 data to see if there is an EOC
391      * marker */
392     gst_adapter_copy (rtpj2kdepay->f_adapter, end, avail - 2, 2);
393
394     if (end[0] != 0xff && end[1] != 0xd9) {
395       end[0] = 0xff;
396       end[1] = 0xd9;
397
398       GST_DEBUG_OBJECT (rtpj2kdepay, "no EOC marker, adding one");
399
400       /* no EOI marker, add one */
401       outbuf = gst_buffer_new_and_alloc (2);
402       gst_buffer_fill (outbuf, 0, end, 2);
403
404       gst_adapter_push (rtpj2kdepay->f_adapter, outbuf);
405       avail += 2;
406     }
407
408     GST_DEBUG_OBJECT (rtpj2kdepay, "pushing buffer of %u bytes", avail);
409     outbuf = gst_adapter_take_buffer (rtpj2kdepay->f_adapter, avail);
410     gst_rtp_drop_meta (GST_ELEMENT_CAST (depayload),
411         outbuf, g_quark_from_static_string (GST_META_TAG_VIDEO_STR));
412     ret = gst_rtp_base_depayload_push (depayload, outbuf);
413   } else {
414     GST_WARNING_OBJECT (rtpj2kdepay, "empty packet");
415     gst_adapter_clear (rtpj2kdepay->f_adapter);
416   }
417
418   /* we accept any mh_id now */
419   rtpj2kdepay->last_mh_id = -1;
420
421   /* reset state */
422   rtpj2kdepay->next_frag = 0;
423   rtpj2kdepay->have_sync = FALSE;
424
425 done:
426   /* we can't keep headers with mh_id of 0 */
427   store_mheader (rtpj2kdepay, 0, NULL);
428
429   return ret;
430 }
431
432 static GstBuffer *
433 gst_rtp_j2k_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
434 {
435   GstRtpJ2KDepay *rtpj2kdepay;
436   guint8 *payload;
437   guint MHF, mh_id, frag_offset, tile, payload_len, j2klen;
438   gint gap;
439   guint32 rtptime;
440
441   rtpj2kdepay = GST_RTP_J2K_DEPAY (depayload);
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
566   return NULL;
567
568   /* ERRORS */
569 empty_packet:
570   {
571     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
572         ("Empty Payload."), (NULL));
573     return NULL;
574   }
575 wrong_mh_id:
576   {
577     GST_ELEMENT_WARNING (rtpj2kdepay, STREAM, DECODE,
578         ("Invalid mh_id %u, expected %u", mh_id, rtpj2kdepay->last_mh_id),
579         (NULL));
580     gst_rtp_j2k_depay_clear_pu (rtpj2kdepay);
581     return NULL;
582   }
583 }
584
585 static void
586 gst_rtp_j2k_depay_set_property (GObject * object, guint prop_id,
587     const 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 void
597 gst_rtp_j2k_depay_get_property (GObject * object, guint prop_id,
598     GValue * value, GParamSpec * pspec)
599 {
600   switch (prop_id) {
601     default:
602       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
603       break;
604   }
605 }
606
607 static GstStateChangeReturn
608 gst_rtp_j2k_depay_change_state (GstElement * element, GstStateChange transition)
609 {
610   GstRtpJ2KDepay *rtpj2kdepay;
611   GstStateChangeReturn ret;
612
613   rtpj2kdepay = GST_RTP_J2K_DEPAY (element);
614
615   switch (transition) {
616     case GST_STATE_CHANGE_NULL_TO_READY:
617       break;
618     case GST_STATE_CHANGE_READY_TO_PAUSED:
619       gst_rtp_j2k_depay_reset (rtpj2kdepay);
620       break;
621     default:
622       break;
623   }
624
625   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
626
627   switch (transition) {
628     case GST_STATE_CHANGE_PAUSED_TO_READY:
629       gst_rtp_j2k_depay_reset (rtpj2kdepay);
630       break;
631     case GST_STATE_CHANGE_READY_TO_NULL:
632       break;
633     default:
634       break;
635   }
636   return ret;
637 }
638
639 gboolean
640 gst_rtp_j2k_depay_plugin_init (GstPlugin * plugin)
641 {
642   return gst_element_register (plugin, "rtpj2kdepay",
643       GST_RANK_SECONDARY, GST_TYPE_RTP_J2K_DEPAY);
644 }