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