gst_plugins_good/gst/qtdemux/gstrtpxqtdepay.c
changeset 26 69c7080681bf
parent 24 bc39b352897e
child 28 4ed5253bb6ba
equal deleted inserted replaced
24:bc39b352897e 26:69c7080681bf
     1 /* GStreamer
       
     2  * Copyright (C) <2006> Wim Taymans <wim@fluendo.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 /*
       
    21  * based on http://developer.apple.com/quicktime/icefloe/dispatch026.html
       
    22  */
       
    23 #ifdef HAVE_CONFIG_H
       
    24 #  include "config.h"
       
    25 #endif
       
    26 
       
    27 #include <gst/rtp/gstrtpbuffer.h>
       
    28 
       
    29 #include <string.h>
       
    30 #include "gstrtpxqtdepay.h"
       
    31 
       
    32 #define MAKE_TLV(a,b)  (((a)<<8)|(b))
       
    33 
       
    34 #define TLV_sd	MAKE_TLV ('s','d')
       
    35 #define TLV_qt	MAKE_TLV ('q','t')
       
    36 #define TLV_ti	MAKE_TLV ('t','i')
       
    37 #define TLV_ly	MAKE_TLV ('l','y')
       
    38 #define TLV_vo	MAKE_TLV ('v','o')
       
    39 #define TLV_mx	MAKE_TLV ('m','x')
       
    40 #define TLV_tr	MAKE_TLV ('t','r')
       
    41 #define TLV_tw	MAKE_TLV ('t','w')
       
    42 #define TLV_th	MAKE_TLV ('t','h')
       
    43 #define TLV_la	MAKE_TLV ('l','a')
       
    44 #define TLV_rt	MAKE_TLV ('r','t')
       
    45 #define TLV_gm	MAKE_TLV ('g','m')
       
    46 #define TLV_oc	MAKE_TLV ('o','c')
       
    47 #define TLV_cr	MAKE_TLV ('c','r')
       
    48 #define TLV_du	MAKE_TLV ('d','u')
       
    49 #define TLV_po	MAKE_TLV ('p','o')
       
    50 
       
    51 #define QT_UINT32(a)  (GST_READ_UINT32_BE(a))
       
    52 #define QT_UINT24(a)  (GST_READ_UINT32_BE(a) >> 8)
       
    53 #define QT_UINT16(a)  (GST_READ_UINT16_BE(a))
       
    54 #define QT_UINT8(a)   (GST_READ_UINT8(a))
       
    55 #define QT_FP32(a)    ((GST_READ_UINT32_BE(a))/65536.0)
       
    56 #define QT_FP16(a)    ((GST_READ_UINT16_BE(a))/256.0)
       
    57 #define QT_FOURCC(a)  (GST_READ_UINT32_LE(a))
       
    58 #define QT_UINT64(a)  ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4))
       
    59 
       
    60 #define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
       
    61 #define FOURCC_avcC     GST_MAKE_FOURCC('a','v','c','C')
       
    62 
       
    63 GST_DEBUG_CATEGORY_STATIC (rtpxqtdepay_debug);
       
    64 #define GST_CAT_DEFAULT (rtpxqtdepay_debug)
       
    65 
       
    66 /* elementfactory information */
       
    67 static const GstElementDetails gst_rtp_xqtdepay_details =
       
    68 GST_ELEMENT_DETAILS ("RTP packet depayloader",
       
    69     "Codec/Depayloader/Network",
       
    70     "Extracts Quicktime audio/video from RTP packets",
       
    71     "Wim Taymans <wim@fluendo.com>");
       
    72 
       
    73 /* RtpXQTDepay signals and args */
       
    74 enum
       
    75 {
       
    76   /* FILL ME */
       
    77   LAST_SIGNAL
       
    78 };
       
    79 
       
    80 enum
       
    81 {
       
    82   ARG_0,
       
    83 };
       
    84 
       
    85 static GstStaticPadTemplate gst_rtp_xqt_depay_src_template =
       
    86 GST_STATIC_PAD_TEMPLATE ("src",
       
    87     GST_PAD_SRC,
       
    88     GST_PAD_ALWAYS,
       
    89     GST_STATIC_CAPS_ANY);
       
    90 
       
    91 static GstStaticPadTemplate gst_rtp_xqt_depay_sink_template =
       
    92 GST_STATIC_PAD_TEMPLATE ("sink",
       
    93     GST_PAD_SINK,
       
    94     GST_PAD_ALWAYS,
       
    95     GST_STATIC_CAPS ("application/x-rtp, "
       
    96         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
       
    97         "media = (string) { \"audio\", \"video\" }, clock-rate = (int) [1, MAX], "
       
    98         "encoding-name = (string) { \"X-QT\", \"X-QUICKTIME\" }")
       
    99     );
       
   100 
       
   101 GST_BOILERPLATE (GstRtpXQTDepay, gst_rtp_xqt_depay, GstBaseRTPDepayload,
       
   102     GST_TYPE_BASE_RTP_DEPAYLOAD);
       
   103 
       
   104 static void gst_rtp_xqt_depay_finalize (GObject * object);
       
   105 
       
   106 static gboolean gst_rtp_xqt_depay_setcaps (GstBaseRTPDepayload * depayload,
       
   107     GstCaps * caps);
       
   108 static GstBuffer *gst_rtp_xqt_depay_process (GstBaseRTPDepayload * depayload,
       
   109     GstBuffer * buf);
       
   110 
       
   111 static GstStateChangeReturn gst_rtp_xqt_depay_change_state (GstElement *
       
   112     element, GstStateChange transition);
       
   113 
       
   114 static void
       
   115 gst_rtp_xqt_depay_base_init (gpointer klass)
       
   116 {
       
   117   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
       
   118 
       
   119   gst_element_class_add_pad_template (element_class,
       
   120       gst_static_pad_template_get (&gst_rtp_xqt_depay_src_template));
       
   121   gst_element_class_add_pad_template (element_class,
       
   122       gst_static_pad_template_get (&gst_rtp_xqt_depay_sink_template));
       
   123 
       
   124   gst_element_class_set_details (element_class, &gst_rtp_xqtdepay_details);
       
   125 }
       
   126 
       
   127 static void
       
   128 gst_rtp_xqt_depay_class_init (GstRtpXQTDepayClass * klass)
       
   129 {
       
   130   GObjectClass *gobject_class;
       
   131   GstElementClass *gstelement_class;
       
   132   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
       
   133 
       
   134   gobject_class = (GObjectClass *) klass;
       
   135   gstelement_class = (GstElementClass *) klass;
       
   136   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
       
   137 
       
   138   parent_class = g_type_class_peek_parent (klass);
       
   139 
       
   140   gobject_class->finalize = gst_rtp_xqt_depay_finalize;
       
   141 
       
   142   gstelement_class->change_state = gst_rtp_xqt_depay_change_state;
       
   143 
       
   144   gstbasertpdepayload_class->set_caps = gst_rtp_xqt_depay_setcaps;
       
   145   gstbasertpdepayload_class->process = gst_rtp_xqt_depay_process;
       
   146 
       
   147   GST_DEBUG_CATEGORY_INIT (rtpxqtdepay_debug, "rtpxqtdepay", 0,
       
   148       "QT Media RTP Depayloader");
       
   149 }
       
   150 
       
   151 static void
       
   152 gst_rtp_xqt_depay_init (GstRtpXQTDepay * rtpxqtdepay,
       
   153     GstRtpXQTDepayClass * klass)
       
   154 {
       
   155   rtpxqtdepay->adapter = gst_adapter_new ();
       
   156 }
       
   157 
       
   158 static void
       
   159 gst_rtp_xqt_depay_finalize (GObject * object)
       
   160 {
       
   161   GstRtpXQTDepay *rtpxqtdepay;
       
   162 
       
   163   rtpxqtdepay = GST_RTP_XQT_DEPAY (object);
       
   164 
       
   165   g_object_unref (rtpxqtdepay->adapter);
       
   166   rtpxqtdepay->adapter = NULL;
       
   167 
       
   168   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   169 }
       
   170 
       
   171 static gboolean
       
   172 gst_rtp_quicktime_parse_sd (GstRtpXQTDepay * rtpxqtdepay, guint8 * data,
       
   173     guint data_len)
       
   174 {
       
   175   gint len;
       
   176   guint32 fourcc;
       
   177 
       
   178   if (data_len < 8)
       
   179     goto too_short;
       
   180 
       
   181   len = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
       
   182   if (len > data_len)
       
   183     goto too_short;
       
   184 
       
   185   fourcc = QT_FOURCC (data + 4);
       
   186 
       
   187   GST_DEBUG_OBJECT (rtpxqtdepay, "parsing %" GST_FOURCC_FORMAT,
       
   188       GST_FOURCC_ARGS (fourcc));
       
   189 
       
   190   switch (fourcc) {
       
   191     case FOURCC_avc1:
       
   192     {
       
   193       guint32 chlen;
       
   194 
       
   195       if (len < 0x56)
       
   196         goto too_short;
       
   197       len -= 0x56;
       
   198       data += 0x56;
       
   199 
       
   200       /* find avcC */
       
   201       while (len >= 8) {
       
   202         chlen = QT_UINT32 (data);
       
   203         fourcc = QT_FOURCC (data + 4);
       
   204         if (fourcc == FOURCC_avcC) {
       
   205           GstBuffer *buf;
       
   206           gint size;
       
   207           GstCaps *caps;
       
   208 
       
   209           GST_DEBUG_OBJECT (rtpxqtdepay, "found avcC codec_data in sd, %u",
       
   210               chlen);
       
   211 
       
   212           /* parse, if found */
       
   213           if (chlen < len)
       
   214             size = chlen - 8;
       
   215           else
       
   216             size = len - 8;
       
   217 
       
   218           buf = gst_buffer_new_and_alloc (size);
       
   219           memcpy (GST_BUFFER_DATA (buf), data + 8, size);
       
   220           caps = gst_caps_new_simple ("video/x-h264",
       
   221               "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
   222           gst_buffer_unref (buf);
       
   223           gst_pad_set_caps (GST_BASE_RTP_DEPAYLOAD (rtpxqtdepay)->srcpad, caps);
       
   224           gst_caps_unref (caps);
       
   225           break;
       
   226         }
       
   227         len -= chlen;
       
   228         data += chlen;
       
   229       }
       
   230       break;
       
   231     }
       
   232     default:
       
   233       break;
       
   234   }
       
   235   return TRUE;
       
   236 
       
   237   /* ERRORS */
       
   238 too_short:
       
   239   {
       
   240     return FALSE;
       
   241   }
       
   242 }
       
   243 
       
   244 static gboolean
       
   245 gst_rtp_xqt_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
       
   246 {
       
   247   GstStructure *structure;
       
   248   gint clock_rate = 90000;      /* default */
       
   249 
       
   250   structure = gst_caps_get_structure (caps, 0);
       
   251 
       
   252   gst_structure_get_int (structure, "clock-rate", &clock_rate);
       
   253   depayload->clock_rate = clock_rate;
       
   254 
       
   255   return TRUE;
       
   256 }
       
   257 
       
   258 static GstBuffer *
       
   259 gst_rtp_xqt_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
       
   260 {
       
   261   GstRtpXQTDepay *rtpxqtdepay;
       
   262   GstBuffer *outbuf;
       
   263   gboolean m;
       
   264 
       
   265   rtpxqtdepay = GST_RTP_XQT_DEPAY (depayload);
       
   266 
       
   267   if (!gst_rtp_buffer_validate (buf))
       
   268     goto bad_packet;
       
   269 
       
   270   if (GST_BUFFER_IS_DISCONT (buf)) {
       
   271     /* discont, clear adapter and try to find a new packet start */
       
   272     gst_adapter_clear (rtpxqtdepay->adapter);
       
   273     rtpxqtdepay->need_resync = TRUE;
       
   274     GST_DEBUG_OBJECT (rtpxqtdepay, "we need resync");
       
   275   }
       
   276 
       
   277   m = gst_rtp_buffer_get_marker (buf);
       
   278   GST_LOG_OBJECT (rtpxqtdepay, "marker: %d", m);
       
   279 
       
   280   {
       
   281     gint payload_len;
       
   282     guint avail;
       
   283     guint8 *payload;
       
   284     guint32 timestamp;
       
   285     guint8 ver, pck;
       
   286     gboolean s, q, l, d;
       
   287 
       
   288     payload_len = gst_rtp_buffer_get_payload_len (buf);
       
   289     payload = gst_rtp_buffer_get_payload (buf);
       
   290 
       
   291     /*                      1                   2                   3 
       
   292      *  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
       
   293      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   294      * | VER   |PCK|S|Q|L| RES         |D| QuickTime Payload ID        |
       
   295      * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   296      */
       
   297     if (payload_len <= 4)
       
   298       goto wrong_length;
       
   299 
       
   300     ver = (payload[0] & 0xf0) >> 4;
       
   301     if (ver > 1)
       
   302       goto wrong_version;
       
   303 
       
   304     pck = (payload[0] & 0x0c) >> 2;
       
   305     if (pck == 0)
       
   306       goto pck_reserved;
       
   307 
       
   308     s = (payload[0] & 0x02) != 0;       /* contains sync sample */
       
   309     q = (payload[0] & 0x01) != 0;       /* has payload description */
       
   310     l = (payload[1] & 0x80) != 0;       /* has packet specific information description */
       
   311     d = (payload[2] & 0x80) != 0;       /* don't cache info for payload id */
       
   312     /* id used for caching info */
       
   313     rtpxqtdepay->current_id = ((payload[2] & 0x7f) << 8) | payload[3];
       
   314 
       
   315     GST_LOG_OBJECT (rtpxqtdepay,
       
   316         "VER: %d, PCK: %d, S: %d, Q: %d, L: %d, D: %d, ID: %d", ver, pck, s, q,
       
   317         l, d, rtpxqtdepay->current_id);
       
   318 
       
   319     if (rtpxqtdepay->need_resync) {
       
   320       /* we need to find the boundary of a new packet after a DISCONT */
       
   321       if (pck != 3 || q) {
       
   322         /* non-fragmented packet or payload description present, packet starts
       
   323          * here. */
       
   324         rtpxqtdepay->need_resync = FALSE;
       
   325       } else {
       
   326         /* fragmented packet without description */
       
   327         if (m) {
       
   328           /* marker bit set, next packet is start of new one */
       
   329           rtpxqtdepay->need_resync = FALSE;
       
   330         }
       
   331         goto need_resync;
       
   332       }
       
   333     }
       
   334 
       
   335     payload += 4;
       
   336     payload_len -= 4;
       
   337 
       
   338     if (q) {
       
   339       gboolean k, f, a, z;
       
   340       guint pdlen, pdpadded;
       
   341       gint padding;
       
   342       guint32 media_type, timescale;
       
   343 
       
   344       /*                      1                   2                   3
       
   345        *  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
       
   346        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   347        * |K|F|A|Z| RES                   | QuickTime Payload Desc Length |
       
   348        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   349        * . QuickTime Payload Desc Data ... . 
       
   350        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   351        */
       
   352       if (payload_len <= 4)
       
   353         goto wrong_length;
       
   354 
       
   355       k = (payload[0] & 0x80) != 0;     /* keyframe */
       
   356       f = (payload[0] & 0x40) != 0;     /* sparse */
       
   357       a = (payload[0] & 0x20) != 0;     /* start of payload */
       
   358       z = (payload[0] & 0x10) != 0;     /* end of payload */
       
   359       pdlen = (payload[2] << 8) | payload[3];
       
   360 
       
   361       if (pdlen < 12)
       
   362         goto wrong_length;
       
   363 
       
   364       /* calc padding */
       
   365       pdpadded = pdlen + 3;
       
   366       pdpadded -= pdpadded % 4;
       
   367       if (payload_len < pdpadded)
       
   368         goto wrong_length;
       
   369 
       
   370       padding = pdpadded - pdlen;
       
   371       GST_LOG_OBJECT (rtpxqtdepay,
       
   372           "K: %d, F: %d, A: %d, Z: %d, len: %d, padding %d", k, f, a, z, pdlen,
       
   373           padding);
       
   374 
       
   375       payload += 4;
       
   376       payload_len -= 4;
       
   377       /*                      1                   2                   3
       
   378        *  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
       
   379        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   380        * | QuickTime Media Type                                          |
       
   381        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   382        * | Timescale                                                     |
       
   383        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   384        * . QuickTime TLVs ... .
       
   385        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   386        */
       
   387       media_type =
       
   388           (payload[0] << 24) | (payload[1] << 16) | (payload[2] << 8) |
       
   389           payload[3];
       
   390       timescale =
       
   391           (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) |
       
   392           payload[7];
       
   393 
       
   394       GST_LOG_OBJECT (rtpxqtdepay, "media_type: %c%c%c%c, timescale %u",
       
   395           payload[0], payload[1], payload[2], payload[3], timescale);
       
   396 
       
   397       payload += 8;
       
   398       payload_len -= 8;
       
   399       pdlen -= 12;
       
   400 
       
   401       /* parse TLV (type-length-value triplets */
       
   402       while (pdlen > 3) {
       
   403         guint16 tlv_len, tlv_type;
       
   404 
       
   405         /*                      1                   2                   3
       
   406          *  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
       
   407          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   408          * | QuickTime TLV Length          | QuickTime TLV Type            |
       
   409          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   410          * . QuickTime TLV Value ... .
       
   411          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   412          */
       
   413         tlv_len = (payload[0] << 8) | payload[1];
       
   414         tlv_type = (payload[2] << 8) | payload[3];
       
   415         pdlen -= 4;
       
   416         if (tlv_len > pdlen)
       
   417           goto wrong_length;
       
   418 
       
   419         GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2],
       
   420             payload[3], tlv_len);
       
   421 
       
   422         payload += 4;
       
   423         payload_len -= 4;
       
   424 
       
   425         switch (tlv_type) {
       
   426           case TLV_sd:
       
   427             /* Session description */
       
   428             if (!gst_rtp_quicktime_parse_sd (rtpxqtdepay, payload, tlv_len))
       
   429               goto unknown_format;
       
   430             rtpxqtdepay->have_sd = TRUE;
       
   431             break;
       
   432           case TLV_qt:
       
   433           case TLV_ti:
       
   434           case TLV_ly:
       
   435           case TLV_vo:
       
   436           case TLV_mx:
       
   437           case TLV_tr:
       
   438           case TLV_tw:
       
   439           case TLV_th:
       
   440           case TLV_la:
       
   441           case TLV_rt:
       
   442           case TLV_gm:
       
   443           case TLV_oc:
       
   444           case TLV_cr:
       
   445           case TLV_du:
       
   446           case TLV_po:
       
   447           default:
       
   448             break;
       
   449         }
       
   450 
       
   451         pdlen -= tlv_len;
       
   452         payload += tlv_len;
       
   453         payload_len -= tlv_len;
       
   454       }
       
   455       payload += padding;
       
   456       payload_len -= padding;
       
   457     }
       
   458 
       
   459     if (l) {
       
   460       guint ssilen, ssipadded;
       
   461       gint padding;
       
   462 
       
   463       /*                      1                   2                   3
       
   464        *  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
       
   465        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   466        * | RES                           | Sample-Specific Info Length   |
       
   467        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   468        * . QuickTime TLVs ... 
       
   469        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   470        */
       
   471       if (payload_len <= 4)
       
   472         goto wrong_length;
       
   473 
       
   474       ssilen = (payload[2] << 8) | payload[3];
       
   475       if (ssilen < 4)
       
   476         goto wrong_length;
       
   477 
       
   478       /* calc padding */
       
   479       ssipadded = ssilen + 3;
       
   480       ssipadded -= ssipadded % 4;
       
   481       if (payload_len < ssipadded)
       
   482         goto wrong_length;
       
   483 
       
   484       padding = ssipadded - ssilen;
       
   485       GST_LOG_OBJECT (rtpxqtdepay, "len: %d, padding %d", ssilen, padding);
       
   486 
       
   487       payload += 4;
       
   488       payload_len -= 4;
       
   489       ssilen -= 4;
       
   490 
       
   491       /* parse TLV (type-length-value triplets */
       
   492       while (ssilen > 3) {
       
   493         guint16 tlv_len, tlv_type;
       
   494 
       
   495         /*                      1                   2                   3
       
   496          *  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
       
   497          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   498          * | QuickTime TLV Length          | QuickTime TLV Type            |
       
   499          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   500          * . QuickTime TLV Value ... .
       
   501          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   502          */
       
   503         tlv_len = (payload[0] << 8) | payload[1];
       
   504         tlv_type = (payload[2] << 8) | payload[3];
       
   505         ssilen -= 4;
       
   506         if (tlv_len > ssilen)
       
   507           goto wrong_length;
       
   508 
       
   509         GST_LOG_OBJECT (rtpxqtdepay, "TLV '%c%c', len %d", payload[2],
       
   510             payload[3], tlv_len);
       
   511 
       
   512         payload += 4;
       
   513         payload_len -= 4;
       
   514 
       
   515         switch (tlv_type) {
       
   516           case TLV_sd:
       
   517           case TLV_qt:
       
   518           case TLV_ti:
       
   519           case TLV_ly:
       
   520           case TLV_vo:
       
   521           case TLV_mx:
       
   522           case TLV_tr:
       
   523           case TLV_tw:
       
   524           case TLV_th:
       
   525           case TLV_la:
       
   526           case TLV_rt:
       
   527           case TLV_gm:
       
   528           case TLV_oc:
       
   529           case TLV_cr:
       
   530           case TLV_du:
       
   531           case TLV_po:
       
   532           default:
       
   533             break;
       
   534         }
       
   535 
       
   536         ssilen -= tlv_len;
       
   537         payload += tlv_len;
       
   538         payload_len -= tlv_len;
       
   539       }
       
   540       payload += padding;
       
   541       payload_len -= padding;
       
   542     }
       
   543 
       
   544     timestamp = gst_rtp_buffer_get_timestamp (buf);
       
   545     rtpxqtdepay->previous_id = rtpxqtdepay->current_id;
       
   546 
       
   547     switch (pck) {
       
   548       case 1:
       
   549       {
       
   550         /* multiple samples per packet. */
       
   551         outbuf = gst_buffer_new_and_alloc (payload_len);
       
   552         memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
       
   553         return outbuf;
       
   554       }
       
   555       case 2:
       
   556       {
       
   557         guint slen, timestamp;
       
   558 
       
   559         /* multiple samples per packet. 
       
   560          *                      1                   2                   3
       
   561          *  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
       
   562          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   563          * |S| Reserved                    | Sample Length                 |
       
   564          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   565          * | Sample Timestamp                                              |
       
   566          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   567          * . Sample Data ...                                               .
       
   568          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   569          * |S| Reserved                    | Sample Length                 |
       
   570          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   571          * | Sample Timestamp                                              |
       
   572          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   573          * . Sample Data ...                                               .
       
   574          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   575          * . ......                                                        .
       
   576          * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       
   577          */
       
   578         while (payload_len > 8) {
       
   579           s = (payload[0] & 0x80) != 0; /* contains sync sample */
       
   580           slen = (payload[2] << 8) | payload[3];
       
   581           timestamp =
       
   582               (payload[4] << 24) | (payload[5] << 16) | (payload[6] << 8) |
       
   583               payload[7];
       
   584 
       
   585           payload += 8;
       
   586           payload_len -= 8;
       
   587 
       
   588           if (slen > payload_len)
       
   589             slen = payload_len;
       
   590 
       
   591           outbuf = gst_buffer_new_and_alloc (slen);
       
   592           memcpy (GST_BUFFER_DATA (outbuf), payload, slen);
       
   593           if (!s)
       
   594             GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
       
   595 
       
   596           gst_base_rtp_depayload_push (depayload, outbuf);
       
   597 
       
   598           /* aligned on 32 bit boundary */
       
   599           slen = GST_ROUND_UP_4 (slen);
       
   600 
       
   601           payload += slen;
       
   602           payload_len -= slen;
       
   603         }
       
   604         break;
       
   605       }
       
   606       case 3:
       
   607       {
       
   608         /* one sample per packet, use adapter to combine based on marker bit. */
       
   609         outbuf = gst_buffer_new_and_alloc (payload_len);
       
   610         memcpy (GST_BUFFER_DATA (outbuf), payload, payload_len);
       
   611 
       
   612         gst_adapter_push (rtpxqtdepay->adapter, outbuf);
       
   613 
       
   614         if (!m)
       
   615           goto done;
       
   616 
       
   617         avail = gst_adapter_available (rtpxqtdepay->adapter);
       
   618         outbuf = gst_adapter_take_buffer (rtpxqtdepay->adapter, avail);
       
   619 
       
   620         GST_DEBUG_OBJECT (rtpxqtdepay,
       
   621             "gst_rtp_xqt_depay_chain: pushing buffer of size %u", avail);
       
   622 
       
   623         return outbuf;
       
   624       }
       
   625     }
       
   626   }
       
   627 
       
   628 done:
       
   629   return NULL;
       
   630 
       
   631 bad_packet:
       
   632   {
       
   633     GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
       
   634         ("Packet did not validate."), (NULL));
       
   635     return NULL;
       
   636   }
       
   637 need_resync:
       
   638   {
       
   639     GST_DEBUG_OBJECT (rtpxqtdepay, "waiting for marker");
       
   640     return NULL;
       
   641   }
       
   642 wrong_version:
       
   643   {
       
   644     GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
       
   645         ("Unknown payload version."), (NULL));
       
   646     return NULL;
       
   647   }
       
   648 pck_reserved:
       
   649   {
       
   650     GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
       
   651         ("PCK reserved 0."), (NULL));
       
   652     return NULL;
       
   653   }
       
   654 wrong_length:
       
   655   {
       
   656     GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
       
   657         ("Wrong payload length."), (NULL));
       
   658     return NULL;
       
   659   }
       
   660 unknown_format:
       
   661   {
       
   662     GST_ELEMENT_WARNING (rtpxqtdepay, STREAM, DECODE,
       
   663         ("Unknown payload format."), (NULL));
       
   664     return NULL;
       
   665   }
       
   666 }
       
   667 
       
   668 static GstStateChangeReturn
       
   669 gst_rtp_xqt_depay_change_state (GstElement * element, GstStateChange transition)
       
   670 {
       
   671   GstRtpXQTDepay *rtpxqtdepay;
       
   672   GstStateChangeReturn ret;
       
   673 
       
   674   rtpxqtdepay = GST_RTP_XQT_DEPAY (element);
       
   675 
       
   676   switch (transition) {
       
   677     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
   678       gst_adapter_clear (rtpxqtdepay->adapter);
       
   679       rtpxqtdepay->previous_id = -1;
       
   680       rtpxqtdepay->current_id = -1;
       
   681       rtpxqtdepay->need_resync = TRUE;
       
   682       rtpxqtdepay->have_sd = FALSE;
       
   683       break;
       
   684     default:
       
   685       break;
       
   686   }
       
   687 
       
   688   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
   689 
       
   690   switch (transition) {
       
   691     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
   692       gst_adapter_clear (rtpxqtdepay->adapter);
       
   693     default:
       
   694       break;
       
   695   }
       
   696   return ret;
       
   697 }
       
   698 
       
   699 gboolean
       
   700 gst_rtp_xqt_depay_plugin_init (GstPlugin * plugin)
       
   701 {
       
   702   return gst_element_register (plugin, "rtpxqtdepay",
       
   703       GST_RANK_MARGINAL, GST_TYPE_RTP_XQT_DEPAY);
       
   704 }