gst/qtdemux/: Cleanup and refactor to make the code more readable.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 12 Jan 2007 10:22:16 +0000 (10:22 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 12 Jan 2007 10:22:16 +0000 (10:22 +0000)
Original commit message from CVS:
* gst/qtdemux/Makefile.am:
* gst/qtdemux/qtdemux.c: (extract_initial_length_and_fourcc),
(gst_qtdemux_loop_state_header), (gst_qtdemux_combine_flows),
(gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
(gst_qtdemux_chain), (qtdemux_sink_activate_pull),
(qtdemux_inflate), (qtdemux_parse_moov), (qtdemux_parse_container),
(qtdemux_parse_node), (qtdemux_tree_get_child_by_type),
(qtdemux_tree_get_sibling_by_type), (gst_qtdemux_add_stream),
(qtdemux_parse_samples), (qtdemux_parse_segments),
(qtdemux_parse_trak), (qtdemux_tag_add_str), (qtdemux_tag_add_num),
(qtdemux_tag_add_date), (qtdemux_tag_add_gnre),
(qtdemux_parse_udta), (qtdemux_redirects_sort_func),
(qtdemux_process_redirects), (qtdemux_parse_redirects),
(qtdemux_parse_tree), (gst_qtdemux_handle_esds),
(qtdemux_video_caps), (qtdemux_audio_caps):
* gst/qtdemux/qtdemux.h:
* gst/qtdemux/qtdemux_dump.c: (qtdemux_dump_mvhd),
(qtdemux_dump_tkhd), (qtdemux_dump_elst), (qtdemux_dump_mdhd),
(qtdemux_dump_hdlr), (qtdemux_dump_vmhd), (qtdemux_dump_dref),
(qtdemux_dump_stsd), (qtdemux_dump_stts), (qtdemux_dump_stss),
(qtdemux_dump_stsc), (qtdemux_dump_stsz), (qtdemux_dump_stco),
(qtdemux_dump_co64), (qtdemux_dump_dcom), (qtdemux_dump_cmvd),
(qtdemux_dump_unknown), (qtdemux_node_dump_foreach),
(qtdemux_node_dump):
* gst/qtdemux/qtdemux_dump.h:
* gst/qtdemux/qtdemux_fourcc.h:
* gst/qtdemux/qtdemux_types.c: (qtdemux_type_get):
* gst/qtdemux/qtdemux_types.h:
* gst/qtdemux/qtpalette.h:
Cleanup and refactor to make the code more readable.
Move debugging/tables into separate files.
Add 2/4/16 color palletee support.
Fix raw 15 bit RGB handling.
Use more FOURCC constants.
Add some docs.

ChangeLog
gst/qtdemux/Makefile.am
gst/qtdemux/qtdemux.c
gst/qtdemux/qtdemux.h
gst/qtdemux/qtdemux_dump.c [new file with mode: 0644]
gst/qtdemux/qtdemux_dump.h [new file with mode: 0644]
gst/qtdemux/qtdemux_fourcc.h [new file with mode: 0644]
gst/qtdemux/qtdemux_types.c [new file with mode: 0644]
gst/qtdemux/qtdemux_types.h [new file with mode: 0644]
gst/qtdemux/qtpalette.h [new file with mode: 0644]

index 80fad93..0fd84c8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,41 @@
+2007-01-12  Wim Taymans  <wim@fluendo.com>
+
+       * gst/qtdemux/Makefile.am:
+       * gst/qtdemux/qtdemux.c: (extract_initial_length_and_fourcc),
+       (gst_qtdemux_loop_state_header), (gst_qtdemux_combine_flows),
+       (gst_qtdemux_loop_state_movie), (gst_qtdemux_loop),
+       (gst_qtdemux_chain), (qtdemux_sink_activate_pull),
+       (qtdemux_inflate), (qtdemux_parse_moov), (qtdemux_parse_container),
+       (qtdemux_parse_node), (qtdemux_tree_get_child_by_type),
+       (qtdemux_tree_get_sibling_by_type), (gst_qtdemux_add_stream),
+       (qtdemux_parse_samples), (qtdemux_parse_segments),
+       (qtdemux_parse_trak), (qtdemux_tag_add_str), (qtdemux_tag_add_num),
+       (qtdemux_tag_add_date), (qtdemux_tag_add_gnre),
+       (qtdemux_parse_udta), (qtdemux_redirects_sort_func),
+       (qtdemux_process_redirects), (qtdemux_parse_redirects),
+       (qtdemux_parse_tree), (gst_qtdemux_handle_esds),
+       (qtdemux_video_caps), (qtdemux_audio_caps):
+       * gst/qtdemux/qtdemux.h:
+       * gst/qtdemux/qtdemux_dump.c: (qtdemux_dump_mvhd),
+       (qtdemux_dump_tkhd), (qtdemux_dump_elst), (qtdemux_dump_mdhd),
+       (qtdemux_dump_hdlr), (qtdemux_dump_vmhd), (qtdemux_dump_dref),
+       (qtdemux_dump_stsd), (qtdemux_dump_stts), (qtdemux_dump_stss),
+       (qtdemux_dump_stsc), (qtdemux_dump_stsz), (qtdemux_dump_stco),
+       (qtdemux_dump_co64), (qtdemux_dump_dcom), (qtdemux_dump_cmvd),
+       (qtdemux_dump_unknown), (qtdemux_node_dump_foreach),
+       (qtdemux_node_dump):
+       * gst/qtdemux/qtdemux_dump.h:
+       * gst/qtdemux/qtdemux_fourcc.h:
+       * gst/qtdemux/qtdemux_types.c: (qtdemux_type_get):
+       * gst/qtdemux/qtdemux_types.h:
+       * gst/qtdemux/qtpalette.h:
+       Cleanup and refactor to make the code more readable.
+       Move debugging/tables into separate files.
+       Add 2/4/16 color palletee support.
+       Fix raw 15 bit RGB handling.
+       Use more FOURCC constants.
+       Add some docs.
+
 2007-01-11  Tim-Philipp Müller  <tim at centricular dot net>
 
        Patch by: Sebastian Dröge  <slomo@circular-chaos.org>
index 1f48036..5e623de 100644 (file)
@@ -4,6 +4,6 @@ plugin_LTLIBRARIES = libgstqtdemux.la
 libgstqtdemux_la_CFLAGS = ${GST_CFLAGS}
 libgstqtdemux_la_LIBADD = $(GST_BASE_LIBS) $(ZLIB_LIBS)
 libgstqtdemux_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS} 
-libgstqtdemux_la_SOURCES = qtdemux.c
+libgstqtdemux_la_SOURCES = qtdemux.c qtdemux_types.c qtdemux_dump.c
 
-noinst_HEADERS = qtdemux.h
+noinst_HEADERS = qtdemux.h qtdemux_types.h qtdemux_dump.h
index acf5861..8d29f1d 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
+/**
+ * SECTION:element-qtdemux
+ *
+ * <refsect2>
+ * <para>
+ * Demuxes a .mov file into raw or compressed audio and/or video streams.
+ * </para>
+ * <para>
+ * This element supports both push and pull-based scheduling, depending on the
+ * capabilities of the upstream elements.
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch filesrc location=test.mov ! qtdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
+ * </programlisting>
+ * Play (parse and decode) a .mov file and try to output it to
+ * an automatically detected soundcard and videosink. If the MOV file contains
+ * compressed audio or video data, this will only work if you have the
+ * right decoder elements/plugins installed.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-12-29 (0.10.5)
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
 #include "gst/gst-i18n-plugin.h"
 
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+#include "qtdemux_fourcc.h"
 #include "qtdemux.h"
+#include "qtpalette.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -44,23 +74,10 @@ GST_DEBUG_CATEGORY_STATIC (qtdemux_debug);
 #define qtdemux_dump_mem(a,b)   /* */
 #endif
 
-#define QTDEMUX_GUINT32_GET(a)  (GST_READ_UINT32_BE(a))
-#define QTDEMUX_GUINT24_GET(a)  (GST_READ_UINT32_BE(a) >> 8)
-#define QTDEMUX_GUINT16_GET(a)  (GST_READ_UINT16_BE(a))
-#define QTDEMUX_GUINT8_GET(a)   (GST_READ_UINT8(a))
-#define QTDEMUX_FP32_GET(a)     ((GST_READ_UINT32_BE(a))/65536.0)
-#define QTDEMUX_FP16_GET(a)     ((GST_READ_UINT16_BE(a))/256.0)
-#define QTDEMUX_FOURCC_GET(a)   (GST_READ_UINT32_LE(a))
-
-#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((guint8 *)a)+4))
-
 typedef struct _QtNode QtNode;
-typedef struct _QtNodeType QtNodeType;
 typedef struct _QtDemuxSegment QtDemuxSegment;
 typedef struct _QtDemuxSample QtDemuxSample;
 
-//typedef struct _QtDemuxStream QtDemuxStream;
-
 struct _QtNode
 {
   guint32 type;
@@ -68,14 +85,6 @@ struct _QtNode
   gint len;
 };
 
-struct _QtNodeType
-{
-  guint32 fourcc;
-  const gchar *name;
-  gint flags;
-  void (*dump) (GstQTDemux * qtdemux, guint8 * buffer, int depth);
-};
-
 struct _QtDemuxSample
 {
   guint32 chunk;
@@ -115,7 +124,7 @@ struct _QtDemuxStream
   guint32 n_samples;
   QtDemuxSample *samples;
   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
-  guint32 min_duration;         /* duration in timescale of dirst sample, used for figuring out
+  guint32 min_duration;         /* duration in timescale of first sample, used for figuring out
                                    the framerate, in timescale units */
 
   /* if we use chunks or samples */
@@ -172,7 +181,7 @@ static const GstElementDetails gst_qtdemux_details =
 GST_ELEMENT_DETAILS ("QuickTime demuxer",
     "Codec/Demuxer",
     "Demultiplex a QuickTime file into audio and video streams",
-    "David Schleef <ds@schleef.org>");
+    "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
 
 static GstStaticPadTemplate gst_qtdemux_sink_template =
     GST_STATIC_PAD_TEMPLATE ("sink",
@@ -195,204 +204,26 @@ GST_STATIC_PAD_TEMPLATE ("video_%02d",
 
 static GstElementClass *parent_class = NULL;
 
-/* we could generate these programmatically, but the generation code
- * is only a few lines shorter than the tables, and much uglier */
-static const guint32 ff_qt_default_palette_256[256] = {
-  0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
-  0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
-  0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
-  0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
-  0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
-  0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
-  0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
-  0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
-  0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
-  0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
-  0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
-  0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
-  0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
-  0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
-  0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
-  0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
-  0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
-  0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
-  0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
-  0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
-  0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
-  0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
-  0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
-  0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
-  0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
-  0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
-  0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
-  0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
-  0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
-  0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
-  0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
-  0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
-  0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
-  0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
-  0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
-  0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
-  0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
-  0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
-  0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
-  0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
-  0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
-  0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
-  0x444444, 0x222222, 0x111111, 0x000000
-};
-
-static const guint32 ff_qt_grayscale_palette_256[256] = {
-  0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
-  0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
-  0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
-  0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
-  0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
-  0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
-  0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
-  0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
-  0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
-  0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
-  0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
-  0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
-  0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
-  0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
-  0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
-  0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
-  0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
-  0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
-  0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
-  0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
-  0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
-  0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
-  0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
-  0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
-  0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
-  0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
-  0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
-  0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
-  0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
-  0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
-  0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
-  0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
-  0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
-  0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
-  0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
-  0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
-  0x030303, 0x020202, 0x010101, 0x000000
-};
-
-#define QT_CONTAINER 1
-
-#define FOURCC_moov     GST_MAKE_FOURCC('m','o','o','v')
-#define FOURCC_mvhd     GST_MAKE_FOURCC('m','v','h','d')
-#define FOURCC_clip     GST_MAKE_FOURCC('c','l','i','p')
-#define FOURCC_trak     GST_MAKE_FOURCC('t','r','a','k')
-#define FOURCC_udta     GST_MAKE_FOURCC('u','d','t','a')
-#define FOURCC_ctab     GST_MAKE_FOURCC('c','t','a','b')
-#define FOURCC_tkhd     GST_MAKE_FOURCC('t','k','h','d')
-#define FOURCC_crgn     GST_MAKE_FOURCC('c','r','g','n')
-#define FOURCC_matt     GST_MAKE_FOURCC('m','a','t','t')
-#define FOURCC_kmat     GST_MAKE_FOURCC('k','m','a','t')
-#define FOURCC_edts     GST_MAKE_FOURCC('e','d','t','s')
-#define FOURCC_elst     GST_MAKE_FOURCC('e','l','s','t')
-#define FOURCC_load     GST_MAKE_FOURCC('l','o','a','d')
-#define FOURCC_tref     GST_MAKE_FOURCC('t','r','e','f')
-#define FOURCC_imap     GST_MAKE_FOURCC('i','m','a','p')
-#define FOURCC___in     GST_MAKE_FOURCC(' ',' ','i','n')
-#define FOURCC___ty     GST_MAKE_FOURCC(' ',' ','t','y')
-#define FOURCC_mdia     GST_MAKE_FOURCC('m','d','i','a')
-#define FOURCC_mdhd     GST_MAKE_FOURCC('m','d','h','d')
-#define FOURCC_hdlr     GST_MAKE_FOURCC('h','d','l','r')
-#define FOURCC_minf     GST_MAKE_FOURCC('m','i','n','f')
-#define FOURCC_vmhd     GST_MAKE_FOURCC('v','m','h','d')
-#define FOURCC_smhd     GST_MAKE_FOURCC('s','m','h','d')
-#define FOURCC_gmhd     GST_MAKE_FOURCC('g','m','h','d')
-#define FOURCC_gmin     GST_MAKE_FOURCC('g','m','i','n')
-#define FOURCC_dinf     GST_MAKE_FOURCC('d','i','n','f')
-#define FOURCC_dref     GST_MAKE_FOURCC('d','r','e','f')
-#define FOURCC_stbl     GST_MAKE_FOURCC('s','t','b','l')
-#define FOURCC_stsd     GST_MAKE_FOURCC('s','t','s','d')
-#define FOURCC_stts     GST_MAKE_FOURCC('s','t','t','s')
-#define FOURCC_stss     GST_MAKE_FOURCC('s','t','s','s')
-#define FOURCC_stsc     GST_MAKE_FOURCC('s','t','s','c')
-#define FOURCC_stsz     GST_MAKE_FOURCC('s','t','s','z')
-#define FOURCC_stco     GST_MAKE_FOURCC('s','t','c','o')
-#define FOURCC_vide     GST_MAKE_FOURCC('v','i','d','e')
-#define FOURCC_soun     GST_MAKE_FOURCC('s','o','u','n')
-#define FOURCC_strm     GST_MAKE_FOURCC('s','t','r','m')
-#define FOURCC_rtsp     GST_MAKE_FOURCC('r','t','s','p')
-#define FOURCC_co64     GST_MAKE_FOURCC('c','o','6','4')
-#define FOURCC_cmov     GST_MAKE_FOURCC('c','m','o','v')
-#define FOURCC_dcom     GST_MAKE_FOURCC('d','c','o','m')
-#define FOURCC_cmvd     GST_MAKE_FOURCC('c','m','v','d')
-#define FOURCC_hint     GST_MAKE_FOURCC('h','i','n','t')
-#define FOURCC_mp4a     GST_MAKE_FOURCC('m','p','4','a')
-#define FOURCC_mp4v     GST_MAKE_FOURCC('m','p','4','v')
-#define FOURCC_wave     GST_MAKE_FOURCC('w','a','v','e')
-#define FOURCC_appl     GST_MAKE_FOURCC('a','p','p','l')
-#define FOURCC_esds     GST_MAKE_FOURCC('e','s','d','s')
-#define FOURCC_hnti     GST_MAKE_FOURCC('h','n','t','i')
-#define FOURCC_rtp_     GST_MAKE_FOURCC('r','t','p',' ')
-#define FOURCC_sdp_     GST_MAKE_FOURCC('s','d','p',' ')
-#define FOURCC_meta     GST_MAKE_FOURCC('m','e','t','a')
-#define FOURCC_ilst     GST_MAKE_FOURCC('i','l','s','t')
-#define FOURCC__nam     GST_MAKE_FOURCC(0xa9,'n','a','m')
-#define FOURCC__ART     GST_MAKE_FOURCC(0xa9,'A','R','T')
-#define FOURCC__wrt     GST_MAKE_FOURCC(0xa9,'w','r','t')
-#define FOURCC__grp     GST_MAKE_FOURCC(0xa9,'g','r','p')
-#define FOURCC__alb     GST_MAKE_FOURCC(0xa9,'a','l','b')
-#define FOURCC__day     GST_MAKE_FOURCC(0xa9,'d','a','y')
-#define FOURCC_gnre     GST_MAKE_FOURCC('g','n','r','e')
-#define FOURCC_disc     GST_MAKE_FOURCC('d','i','s','c')
-#define FOURCC_disk     GST_MAKE_FOURCC('d','i','s','k')
-#define FOURCC_trkn     GST_MAKE_FOURCC('t','r','k','n')
-#define FOURCC_cpil     GST_MAKE_FOURCC('c','p','i','l')
-#define FOURCC_tmpo     GST_MAKE_FOURCC('t','m','p','o')
-#define FOURCC__too     GST_MAKE_FOURCC(0xa9,'t','o','o')
-#define FOURCC_____     GST_MAKE_FOURCC('-','-','-','-')
-#define FOURCC_free     GST_MAKE_FOURCC('f','r','e','e')
-#define FOURCC_data     GST_MAKE_FOURCC('d','a','t','a')
-#define FOURCC_SVQ3     GST_MAKE_FOURCC('S','V','Q','3')
-#define FOURCC_rmra     GST_MAKE_FOURCC('r','m','r','a')
-#define FOURCC_rmda     GST_MAKE_FOURCC('r','m','d','a')
-#define FOURCC_rdrf     GST_MAKE_FOURCC('r','d','r','f')
-#define FOURCC__gen     GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
-#define FOURCC_rmdr     GST_MAKE_FOURCC('r','m','d','r')
-#define FOURCC_rmvc     GST_MAKE_FOURCC('r','m','v','c')
-#define FOURCC_qtim     GST_MAKE_FOURCC('q','t','i','m')
-
-
 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
 static void gst_qtdemux_dispose (GObject * object);
+
 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
     GstStateChange transition);
-static void gst_qtdemux_loop (GstPad * pad);
-static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
+
+static void gst_qtdemux_loop (GstPad * pad);
+static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
 
-static void qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer,
-    int length);
-static void qtdemux_parse (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
+static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer,
     int length);
-static const QtNodeType *qtdemux_type_get (guint32 fourcc);
-static void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
-static void qtdemux_parse_tree (GstQTDemux * qtdemux);
-static void qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta);
-static void qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
-    GNode * node);
-static void qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
-    const char *tag2, GNode * node);
-static void qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag,
-    GNode * node);
-static void qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag,
-    GNode * node);
+static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
+    guint8 * buffer, int length);
+static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
 
 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
     QtDemuxStream * stream, GNode * esds, GstTagList * list);
@@ -1095,9 +926,9 @@ extract_initial_length_and_fourcc (guint8 * data, guint64 * plength,
   guint64 length;
   guint32 fourcc;
 
-  length = GST_READ_UINT32_BE (data);
+  length = QT_UINT32 (data);
   GST_DEBUG ("length %08" G_GINT64_MODIFIER "x", length);
-  fourcc = GST_READ_UINT32_LE (data + 4);
+  fourcc = QT_FOURCC (data + 4);
   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
 
   if (length == 0) {
@@ -1105,7 +936,7 @@ extract_initial_length_and_fourcc (guint8 * data, guint64 * plength,
   } else if (length == 1) {
     /* this means we have an extended size, which is the 64 bit value of
      * the next 8 bytes */
-    length = GST_READ_UINT64_BE (data + 8);
+    length = QT_UINT64 (data + 8);
     GST_DEBUG ("length %08llx", length);
   }
 
@@ -1131,26 +962,31 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
   gst_buffer_unref (buf);
 
   switch (fourcc) {
-    case GST_MAKE_FOURCC ('m', 'd', 'a', 't'):
-    case GST_MAKE_FOURCC ('f', 'r', 'e', 'e'):
-    case GST_MAKE_FOURCC ('w', 'i', 'd', 'e'):
-    case GST_MAKE_FOURCC ('P', 'I', 'C', 'T'):
-    case GST_MAKE_FOURCC ('p', 'n', 'o', 't'):
-      GST_LOG ("skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
+    case FOURCC_mdat:
+    case FOURCC_free:
+    case FOURCC_wide:
+    case FOURCC_PICT:
+    case FOURCC_pnot:
+    {
+      GST_LOG_OBJECT (qtdemux,
+          "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
           GST_FOURCC_ARGS (fourcc), cur_offset);
       cur_offset += length;
       qtdemux->offset += length;
       break;
-    case GST_MAKE_FOURCC ('m', 'o', 'o', 'v'):{
+    }
+    case FOURCC_moov:
+    {
       GstBuffer *moov;
 
       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
       if (ret != GST_FLOW_OK)
         goto beach;
       if (length != GST_BUFFER_SIZE (moov)) {
-        GST_WARNING_OBJECT (qtdemux,
-            "We got less than expected (received %u, wanted %u)",
-            GST_BUFFER_SIZE (moov), (guint) length);
+        GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
+            (_("This file is incomplete and cannot be played.")),
+            ("We got less than expected (received %u, wanted %u)",
+                GST_BUFFER_SIZE (moov), (guint) length));
         ret = GST_FLOW_ERROR;
         goto beach;
       }
@@ -1158,9 +994,8 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
       qtdemux->offset += length;
 
       qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
-      if (1) {
-        qtdemux_node_dump (qtdemux, qtdemux->moov_node);
-      }
+      qtdemux_node_dump (qtdemux, qtdemux->moov_node);
+
       qtdemux_parse_tree (qtdemux);
       g_node_destroy (qtdemux->moov_node);
       gst_buffer_unref (moov);
@@ -1170,9 +1005,11 @@ gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
           qtdemux->state);
       break;
     }
-    default:{
-      GST_LOG ("unknown %08x '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
-          fourcc, GST_FOURCC_ARGS (fourcc), cur_offset);
+    default:
+    {
+      GST_LOG_OBJECT (qtdemux,
+          "unknown %08x '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT, fourcc,
+          GST_FOURCC_ARGS (fourcc), cur_offset);
       cur_offset += length;
       qtdemux->offset += length;
       break;
@@ -1393,10 +1230,6 @@ gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
   /* store the value */
   stream->last_ret = ret;
 
-  /* if it's success we can return the value right away */
-  if (GST_FLOW_IS_SUCCESS (ret))
-    goto done;
-
   /* any other error that is not-linked can be returned right
    * away */
   if (ret != GST_FLOW_NOT_LINKED)
@@ -1495,33 +1328,32 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
   }
 
-  /* we're going to modify the metadata */
-  buf = gst_buffer_make_metadata_writable (buf);
+  qtdemux->last_ts = min_time;
+  gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, min_time);
 
-  if (stream->discont) {
-    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
-    stream->discont = FALSE;
-  }
+  if (stream->pad) {
+    /* we're going to modify the metadata */
+    buf = gst_buffer_make_metadata_writable (buf);
 
-  GST_BUFFER_TIMESTAMP (buf) = timestamp;
-  GST_BUFFER_DURATION (buf) = duration;
+    if (stream->discont) {
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
+      stream->discont = FALSE;
+    }
 
-  qtdemux->last_ts = min_time;
-  gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, min_time);
+    GST_BUFFER_TIMESTAMP (buf) = timestamp;
+    GST_BUFFER_DURATION (buf) = duration;
 
-  if (!keyframe)
-    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
+    if (!keyframe)
+      GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
 
-  gst_buffer_set_caps (buf, stream->caps);
+    gst_buffer_set_caps (buf, stream->caps);
 
-  if (stream->pad) {
     GST_LOG_OBJECT (qtdemux,
         "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
         GST_TIME_FORMAT " on pad %p", GST_TIME_ARGS (timestamp),
         GST_TIME_ARGS (duration), stream->pad);
     ret = gst_pad_push (stream->pad, buf);
   } else {
-    gst_buffer_unref (buf);
     ret = GST_FLOW_OK;
   }
 
@@ -1600,6 +1432,12 @@ pause:
     if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
       /* check EOS */
       if (ret == GST_FLOW_UNEXPECTED) {
+        if (qtdemux->n_streams == 0) {
+          /* we have no streams, post an error */
+          GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
+              (_("This file contains no playable streams.")),
+              ("no known streams found"));
+        }
         if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
           gint64 stop;
 
@@ -1614,15 +1452,10 @@ pause:
           GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
           gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
         }
-        if (qtdemux->n_streams == 0) {
-          /* we have no streams, post an error */
-          GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
-              (NULL), ("no known streams found"));
-        }
       } else {
-        gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
         GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
             (NULL), ("streaming stopped, reason %s", reason));
+        gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
       }
     }
     goto done;
@@ -1724,7 +1557,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
         GST_DEBUG_OBJECT (demux,
             "Peeking found [%" GST_FOURCC_FORMAT "] size: %u",
             GST_FOURCC_ARGS (fourcc), (guint) size);
-        if ((fourcc == GST_MAKE_FOURCC ('m', 'd', 'a', 't'))) {
+        if (fourcc == FOURCC_mdat) {
           if (demux->n_streams > 0) {
             demux->state = QTDEMUX_STATE_MOVIE;
             demux->neededbytes = next_entry_size (demux);
@@ -1749,7 +1582,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
 
         /* parse the header */
         extract_initial_length_and_fourcc (data, NULL, &fourcc);
-        if (fourcc == GST_MAKE_FOURCC ('m', 'o', 'o', 'v')) {
+        if (fourcc == FOURCC_moov) {
           GST_DEBUG_OBJECT (demux, "Parsing [moov]");
 
           qtdemux_parse_moov (demux, data, demux->neededbytes);
@@ -1773,7 +1606,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
               demux->n_streams, demux->mdatbuffer);
           gst_adapter_clear (demux->adapter);
           GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
-              GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
+              GST_FOURCC_ARGS (QT_UINT32 (demux->mdatbuffer)));
           gst_adapter_push (demux->adapter, demux->mdatbuffer);
           demux->mdatbuffer = NULL;
           demux->offset = demux->mdatoffset;
@@ -1798,7 +1631,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
             gst_adapter_take (demux->adapter, demux->neededbytes),
             demux->neededbytes);
         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
-            GST_FOURCC_ARGS (GST_READ_UINT32_BE (demux->mdatbuffer)));
+            GST_FOURCC_ARGS (QT_UINT32 (demux->mdatbuffer)));
         demux->offset += demux->neededbytes;
         demux->neededbytes = 16;
         demux->state = QTDEMUX_STATE_INITIAL;
@@ -1899,7 +1732,6 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
         demux->neededbytes);
   }
-
 done:
   gst_object_unref (demux);
 
@@ -1942,7 +1774,6 @@ qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
 
   if (active) {
-    /* if we have a scheduler we can start the task */
     demux->pullbased = TRUE;
     demux->segment_running = TRUE;
     gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop, sinkpad);
@@ -1964,133 +1795,7 @@ qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
   return TRUE;
 }
 
-static void qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-static void qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer,
-    int depth);
-
-static const QtNodeType qt_node_types[] = {
-  {FOURCC_moov, "movie", QT_CONTAINER,},
-  {FOURCC_mvhd, "movie header", 0,
-      qtdemux_dump_mvhd},
-  {FOURCC_clip, "clipping", QT_CONTAINER,},
-  {FOURCC_trak, "track", QT_CONTAINER,},
-  {FOURCC_udta, "user data", QT_CONTAINER,},    /* special container */
-  {FOURCC_ctab, "color table", 0,},
-  {FOURCC_tkhd, "track header", 0,
-      qtdemux_dump_tkhd},
-  {FOURCC_crgn, "clipping region", 0,},
-  {FOURCC_matt, "track matte", QT_CONTAINER,},
-  {FOURCC_kmat, "compressed matte", 0,},
-  {FOURCC_edts, "edit", QT_CONTAINER,},
-  {FOURCC_elst, "edit list", 0,
-      qtdemux_dump_elst},
-  {FOURCC_load, "track load settings", 0,},
-  {FOURCC_tref, "track reference", QT_CONTAINER,},
-  {FOURCC_imap, "track input map", QT_CONTAINER,},
-  {FOURCC___in, "track input", 0,},     /* special container */
-  {FOURCC___ty, "input type", 0,},
-  {FOURCC_mdia, "media", QT_CONTAINER},
-  {FOURCC_mdhd, "media header", 0,
-      qtdemux_dump_mdhd},
-  {FOURCC_hdlr, "handler reference", 0,
-      qtdemux_dump_hdlr},
-  {FOURCC_minf, "media information", QT_CONTAINER},
-  {FOURCC_vmhd, "video media information", 0,
-      qtdemux_dump_vmhd},
-  {FOURCC_smhd, "sound media information", 0},
-  {FOURCC_gmhd, "base media information header", 0},
-  {FOURCC_gmin, "base media info", 0},
-  {FOURCC_dinf, "data information", QT_CONTAINER},
-  {FOURCC_dref, "data reference", 0,
-      qtdemux_dump_dref},
-  {FOURCC_stbl, "sample table", QT_CONTAINER},
-  {FOURCC_stsd, "sample description", 0,
-      qtdemux_dump_stsd},
-  {FOURCC_stts, "time-to-sample", 0,
-      qtdemux_dump_stts},
-  {FOURCC_stss, "sync sample", 0,
-      qtdemux_dump_stss},
-  {FOURCC_stsc, "sample-to-chunk", 0,
-      qtdemux_dump_stsc},
-  {FOURCC_stsz, "sample size", 0,
-      qtdemux_dump_stsz},
-  {FOURCC_stco, "chunk offset", 0,
-      qtdemux_dump_stco},
-  {FOURCC_co64, "64-bit chunk offset", 0,
-      qtdemux_dump_co64},
-  {FOURCC_vide, "video media", 0},
-  {FOURCC_cmov, "compressed movie", QT_CONTAINER},
-  {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
-  {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
-  {FOURCC_hint, "hint", 0,},
-  {FOURCC_mp4a, "mp4a", 0,},
-  {FOURCC_mp4v, "mp4v", 0,},
-  {FOURCC_wave, "wave", QT_CONTAINER},
-  {FOURCC_appl, "appl", QT_CONTAINER},
-  {FOURCC_esds, "esds", 0},
-  {FOURCC_hnti, "hnti", QT_CONTAINER},
-  {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
-  {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
-  {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
-  {FOURCC_ilst, "ilst", QT_CONTAINER,},
-  {FOURCC__nam, "Name", QT_CONTAINER,},
-  {FOURCC__ART, "Artist", QT_CONTAINER,},
-  {FOURCC__wrt, "Writer", QT_CONTAINER,},
-  {FOURCC__grp, "Group", QT_CONTAINER,},
-  {FOURCC__alb, "Album", QT_CONTAINER,},
-  {FOURCC__day, "Date", QT_CONTAINER,},
-  {FOURCC_gnre, "Genre", QT_CONTAINER,},
-  {FOURCC_trkn, "Track Number", QT_CONTAINER,},
-  {FOURCC_disc, "Disc Number", QT_CONTAINER,},
-  {FOURCC_disk, "Disc Number", QT_CONTAINER,},
-  {FOURCC_cpil, "cpil", QT_CONTAINER,},
-  {FOURCC_tmpo, "Tempo", QT_CONTAINER,},
-  {FOURCC__too, "too", QT_CONTAINER,},
-  {FOURCC_____, "----", QT_CONTAINER,},
-  {FOURCC_data, "data", 0, qtdemux_dump_unknown},
-  {FOURCC_free, "free", 0,},
-  {FOURCC_SVQ3, "SVQ3", 0,},
-  {FOURCC_rmra, "rmra", QT_CONTAINER,},
-  {FOURCC_rmda, "rmda", QT_CONTAINER,},
-  {FOURCC_rdrf, "rdrf", 0,},
-  {FOURCC__gen, "Custom Genre", QT_CONTAINER,},
-  {0, "unknown", 0},
-};
-static int n_qt_node_types = sizeof (qt_node_types) / sizeof (qt_node_types[0]);
-
 #ifdef HAVE_ZLIB
-
 static void *
 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
 {
@@ -2138,10 +1843,9 @@ qtdemux_inflate (void *z_buffer, int z_length, int length)
   g_free (z);
   return buffer;
 }
-
 #endif /* HAVE_ZLIB */
 
-static void
+static gboolean
 qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
 {
   GNode *cmov;
@@ -2149,7 +1853,7 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
   qtdemux->moov_node = g_node_new (buffer);
 
   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
-  qtdemux_parse (qtdemux, qtdemux->moov_node, buffer, length);
+  qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
 
   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
   if (cmov) {
@@ -2159,8 +1863,10 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
 
     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
+    if (dcom == NULL || cmvd == NULL)
+      goto invalid_compression;
 
-    method = QTDEMUX_FOURCC_GET ((guint8 *) dcom->data + 8);
+    method = QT_FOURCC ((guint8 *) dcom->data + 8);
     switch (method) {
 #ifdef HAVE_ZLIB
       case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
@@ -2168,9 +1874,8 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
         int compressed_length;
         guint8 *buf;
 
-        uncompressed_length = QTDEMUX_GUINT32_GET ((guint8 *) cmvd->data + 8);
-        compressed_length =
-            QTDEMUX_GUINT32_GET ((guint8 *) cmvd->data + 4) - 12;
+        uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
+        compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
         GST_LOG ("length = %d", uncompressed_length);
 
         buf =
@@ -2180,7 +1885,8 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
         qtdemux->moov_node_compressed = qtdemux->moov_node;
         qtdemux->moov_node = g_node_new (buf);
 
-        qtdemux_parse (qtdemux, qtdemux->moov_node, buf, uncompressed_length);
+        qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
+            uncompressed_length);
         break;
       }
 #endif /* HAVE_ZLIB */
@@ -2190,786 +1896,248 @@ qtdemux_parse_moov (GstQTDemux * qtdemux, guint8 * buffer, int length)
         break;
     }
   }
+  return TRUE;
+
+  /* ERRORS */
+invalid_compression:
+  {
+    GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
+    return FALSE;
+  }
+}
+
+static gboolean
+qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, guint8 * buf,
+    guint8 * end)
+{
+  while (buf < end) {
+    GNode *child;
+    guint32 len;
+
+    if (buf + 4 > end) {
+      GST_LOG_OBJECT (qtdemux, "buffer overrun");
+      break;
+    }
+    len = QT_UINT32 (buf);
+    if (len == 0) {
+      GST_LOG_OBJECT (qtdemux, "empty container");
+      break;
+    }
+    if (len < 8) {
+      GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
+      break;
+    }
+    if (len > (end - buf)) {
+      GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len, end - buf);
+      break;
+    }
+
+    child = g_node_new (buf);
+    g_node_append (node, child);
+    qtdemux_parse_node (qtdemux, child, buf, len);
+
+    buf += len;
+  }
+  return TRUE;
 }
 
-static void
-qtdemux_parse (GstQTDemux * qtdemux, GNode * node, guint8 * buffer, int length)
+static gboolean
+qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, guint8 * buffer,
+    int length)
 {
   guint32 fourcc;
   guint32 node_length;
   const QtNodeType *type;
   guint8 *end;
 
-  GST_LOG ("qtdemux_parse buffer %p length %d", buffer, length);
+  GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %d", buffer, length);
 
-  node_length = QTDEMUX_GUINT32_GET (buffer);
-  fourcc = QTDEMUX_FOURCC_GET (buffer + 4);
+  node_length = QT_UINT32 (buffer);
+  fourcc = QT_FOURCC (buffer + 4);
 
   type = qtdemux_type_get (fourcc);
 
+  /* ignore empty nodes */
   if (fourcc == 0 || node_length == 8)
-    return;
-
-  GST_LOG ("parsing '%" GST_FOURCC_FORMAT "', length=%d",
-      GST_FOURCC_ARGS (fourcc), node_length);
-
-  if (type->flags & QT_CONTAINER) {
-    guint8 *buf;
-    guint32 len;
-
-    buf = buffer + 8;
-    end = buffer + length;
-    while (buf < end) {
-      GNode *child;
+    return TRUE;
 
-      if (buf + 8 >= end) {
-        /* FIXME: get annoyed */
-        GST_LOG ("buffer overrun");
-      }
-      len = QTDEMUX_GUINT32_GET (buf);
-      if (len < 8) {
-        GST_WARNING ("atom length too short (%d < 8)", len);
-        break;
-      }
-      if (len > (end - buf)) {
-        GST_WARNING ("atom length too long (%d > %d)", len, end - buf);
-        break;
-      }
+  end = buffer + length;
 
-      child = g_node_new (buf);
-      g_node_append (node, child);
-      qtdemux_parse (qtdemux, child, buf, len);
+  GST_LOG_OBJECT (qtdemux,
+      "parsing '%" GST_FOURCC_FORMAT "', length=%d, name '%s'",
+      GST_FOURCC_ARGS (fourcc), node_length, type->name);
 
-      buf += len;
-    }
+  if (type->flags & QT_FLAG_CONTAINER) {
+    qtdemux_parse_container (qtdemux, node, buffer + 8, end);
   } else {
-    if (fourcc == FOURCC_stsd) {
-      guint8 *buf;
-      guint32 len;
-
-      GST_DEBUG_OBJECT (qtdemux,
-          "parsing stsd (sample table, sample description) atom");
-      buf = buffer + 16;
-      end = buffer + length;
-      while (buf < end) {
-        GNode *child;
-
-        if (buf + 8 >= end) {
-          /* FIXME: get annoyed */
-          GST_LOG ("buffer overrun");
-        }
-        len = QTDEMUX_GUINT32_GET (buf);
-        if (len < 8) {
-          GST_WARNING ("length too short (%d < 8)", len);
-          break;
-        }
-        if (len > (end - buf)) {
-          GST_WARNING ("length too long (%d > %d)", len, end - buf);
+    switch (fourcc) {
+      case FOURCC_stsd:
+      {
+        if (node_length < 20) {
+          GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
           break;
         }
-
-        child = g_node_new (buf);
-        g_node_append (node, child);
-        qtdemux_parse (qtdemux, child, buf, len);
-
-        buf += len;
-      }
-    } else if (fourcc == FOURCC_mp4a) {
-      guint8 *buf;
-      guint32 len;
-      guint32 version;
-
-      version = QTDEMUX_GUINT32_GET (buffer + 16);
-      if (version == 0x00010000 || 1) {
-        buf = buffer + 0x24;
-        end = buffer + length;
-
-        while (buf < end) {
-          GNode *child;
-
-          if (buf + 8 >= end) {
-            /* FIXME: get annoyed */
-            GST_LOG ("buffer overrun");
-          }
-          len = QTDEMUX_GUINT32_GET (buf);
-          if (len < 8) {
-            GST_WARNING ("length too short (%d < 8)", len);
-            break;
-          }
-          if (len > (end - buf)) {
-            GST_WARNING ("length too long (%d > %d)", len, end - buf);
-            break;
-          }
-
-          child = g_node_new (buf);
-          g_node_append (node, child);
-          qtdemux_parse (qtdemux, child, buf, len);
-
-          buf += len;
-        }
-      } else {
-        GST_WARNING ("unhandled mp4a version 0x%08x", version);
+        GST_DEBUG_OBJECT (qtdemux,
+            "parsing stsd (sample table, sample description) atom");
+        qtdemux_parse_container (qtdemux, node, buffer + 16, end);
+        break;
       }
-    } else if (fourcc == FOURCC_mp4v) {
-      guint8 *buf;
-      guint32 len;
-      guint32 version;
-      int tlen;
-
-      GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
-      version = QTDEMUX_GUINT32_GET (buffer + 16);
-      GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
-      if (1 || version == 0x00000000) {
-
-        buf = buffer + 0x32;
-        end = buffer + length;
-
-        /* FIXME Quicktime uses PASCAL string while
-         * the iso format uses C strings. Check the file
-         * type before attempting to parse the string here. */
-        tlen = QTDEMUX_GUINT8_GET (buf);
-        GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
-        buf++;
-        GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
-        /* the string has a reserved space of 32 bytes so skip
-         * the remaining 31 */
-        buf += 31;
-        buf += 4;               /* and 4 bytes reserved */
-
-        qtdemux_dump_mem (buf, end - buf);
-        while (buf < end) {
-          GNode *child;
-
-          if (buf + 8 >= end) {
-            /* FIXME: get annoyed */
-            GST_LOG ("buffer overrun");
-          }
-          len = QTDEMUX_GUINT32_GET (buf);
-          if (len == 0)
-            break;
-          if (len < 8) {
-            GST_WARNING ("length too short (%d < 8)", len);
-            break;
-          }
-          if (len > (end - buf)) {
-            GST_WARNING ("length too long (%d > %d)", len, end - buf);
-            break;
-          }
-
-          child = g_node_new (buf);
-          g_node_append (node, child);
-          qtdemux_parse (qtdemux, child, buf, len);
+      case FOURCC_mp4a:
+      {
+        guint32 version;
+        guint32 offset;
 
-          buf += len;
-        }
-      }
-    } else if (fourcc == FOURCC_meta) {
-      guint8 *buf;
-      guint32 len;
-
-      buf = buffer + 12;
-      end = buffer + length;
-      while (buf < end) {
-        GNode *child;
-
-        if (buf + 8 >= end) {
-          /* FIXME: get annoyed */
-          GST_LOG ("buffer overrun");
-        }
-        len = QTDEMUX_GUINT32_GET (buf);
-        if (len < 8) {
-          GST_WARNING ("length too short (%d < 8)", len);
-          break;
-        }
-        if (len > (end - buf)) {
-          GST_WARNING ("length too long (%d > %d)", len, end - buf);
+        if (length < 20) {
+          GST_LOG_OBJECT (qtdemux, "skipping small mp4a box");
           break;
         }
+        version = QT_UINT32 (buffer + 16);
 
-        child = g_node_new (buf);
-        g_node_append (node, child);
-        qtdemux_parse (qtdemux, child, buf, len);
+        GST_WARNING_OBJECT (qtdemux, "mp4a version 0x%08x", version);
 
-        buf += len;
-      }
-    } else if (fourcc == FOURCC_SVQ3) {
-      guint8 *buf;
-      guint32 len;
-      guint32 version;
-      int tlen;
-
-      GST_LOG ("parsing in SVQ3");
-      buf = buffer + 12;
-      end = buffer + length;
-      version = QTDEMUX_GUINT32_GET (buffer + 16);
-      GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
-      if (1 || version == 0x00000000) {
-
-        buf = buffer + 0x32;
-        end = buffer + length;
-
-        tlen = QTDEMUX_GUINT8_GET (buf);
-        GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
-        buf++;
-        GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
-        buf += tlen;
-        buf += 23;
-
-        qtdemux_dump_mem (buf, end - buf);
-        while (buf < end) {
-          GNode *child;
-
-          if (buf + 8 >= end) {
-            /* FIXME: get annoyed */
-            GST_LOG ("buffer overrun");
-          }
-          len = QTDEMUX_GUINT32_GET (buf);
-          if (len == 0)
+        /* parse any esds descriptors */
+        switch (version) {
+          case 0x00000000:
+          case 0x00010000:
+            offset = 0x24;
             break;
-          if (len < 8) {
-            GST_WARNING ("length too short (%d < 8)", len);
+          case 0x00020000:
+            offset = 0x48;
             break;
-          }
-          if (len > (end - buf)) {
-            GST_WARNING ("length too long (%d > %d)", len, end - buf);
+          default:
+            GST_WARNING_OBJECT (qtdemux, "unhandled mp4a version 0x%08x",
+                version);
+            offset = 0;
             break;
-          }
-
-          child = g_node_new (buf);
-          g_node_append (node, child);
-          qtdemux_parse (qtdemux, child, buf, len);
-
-          buf += len;
         }
+        if (offset)
+          qtdemux_parse_container (qtdemux, node, buffer + offset, end);
+        break;
       }
-    }
-#if 0
-    if (fourcc == FOURCC_cmvd) {
-      int uncompressed_length;
-      guint8 *buf;
-
-      uncompressed_length = QTDEMUX_GUINT32_GET (buffer + 8);
-      GST_LOG ("length = %d", uncompressed_length);
-
-      buf =
-          qtdemux_inflate (buffer + 12, node_length - 12, uncompressed_length);
-
-      end = buf + uncompressed_length;
-      while (buf < end) {
-        GNode *child;
-        guint32 len;
-
-        if (buf + 8 >= end) {
-          /* FIXME: get annoyed */
-          GST_LOG ("buffer overrun");
+      case FOURCC_mp4v:
+      {
+        guint8 *buf;
+        guint32 version;
+        int tlen;
+
+        GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
+        version = QT_UINT32 (buffer + 16);
+        GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
+        if (1 || version == 0x00000000) {
+          buf = buffer + 0x32;
+
+          /* FIXME Quicktime uses PASCAL string while
+           * the iso format uses C strings. Check the file
+           * type before attempting to parse the string here. */
+          tlen = QT_UINT8 (buf);
+          GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
+          buf++;
+          GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
+          /* the string has a reserved space of 32 bytes so skip
+           * the remaining 31 */
+          buf += 31;
+          buf += 4;             /* and 4 bytes reserved */
+
+          qtdemux_dump_mem (buf, end - buf);
+
+          qtdemux_parse_container (qtdemux, node, buf, end);
         }
-        len = QTDEMUX_GUINT32_GET (buf);
-
-        child = g_node_new (buf);
-        g_node_append (node, child);
-        qtdemux_parse (qtdemux, child, buf, len);
-
-        buf += len;
+        break;
       }
+      case FOURCC_meta:
+      {
+        GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
+        qtdemux_parse_container (qtdemux, node, buffer + 12, end);
+        break;
+      }
+      default:
+        break;
     }
-#endif
-  }
-}
-
-static const QtNodeType *
-qtdemux_type_get (guint32 fourcc)
-{
-  int i;
-
-  for (i = 0; i < n_qt_node_types; i++) {
-    if (qt_node_types[i].fourcc == fourcc)
-      return qt_node_types + i;
   }
-
-  GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
+  GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT,
       GST_FOURCC_ARGS (fourcc));
-  return qt_node_types + n_qt_node_types - 1;
+  return TRUE;
 }
 
-static gboolean
-qtdemux_node_dump_foreach (GNode * node, gpointer qtdemux)
+static GNode *
+qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
 {
-  guint8 *buffer = (guint8 *) node->data;
-  guint32 node_length;
-  guint32 fourcc;
-  const QtNodeType *type;
-  int depth;
-
-  node_length = GST_READ_UINT32_BE (buffer);
-  fourcc = GST_READ_UINT32_LE (buffer + 4);
-
-  type = qtdemux_type_get (fourcc);
-
-  depth = (g_node_depth (node) - 1) * 2;
-  GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
-      depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
-
-  if (type->dump)
-    type->dump (GST_QT_DEMUX_CAST (qtdemux), buffer, depth);
+  GNode *child;
+  guint8 *buffer;
+  guint32 child_fourcc;
 
-  return FALSE;
-}
+  for (child = g_node_first_child (node); child;
+      child = g_node_next_sibling (child)) {
+    buffer = (guint8 *) child->data;
 
-static void
-qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
-{
-  g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
-      qtdemux_node_dump_foreach, qtdemux);
-}
+    child_fourcc = QT_FOURCC (buffer + 4);
 
-static void
-qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  creation time: %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  GST_LOG ("%*s  modify time:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 16));
-  GST_LOG ("%*s  time scale:    1/%u sec", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 20));
-  GST_LOG ("%*s  duration:      %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 24));
-  GST_LOG ("%*s  pref. rate:    %g", depth, "", QTDEMUX_FP32_GET (buffer + 28));
-  GST_LOG ("%*s  pref. volume:  %g", depth, "", QTDEMUX_FP16_GET (buffer + 32));
-  GST_LOG ("%*s  preview time:  %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 80));
-  GST_LOG ("%*s  preview dur.:  %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 84));
-  GST_LOG ("%*s  poster time:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 88));
-  GST_LOG ("%*s  select time:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 92));
-  GST_LOG ("%*s  select dur.:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 96));
-  GST_LOG ("%*s  current time:  %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 100));
-  GST_LOG ("%*s  next track ID: %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 104));
+    if (child_fourcc == fourcc) {
+      return child;
+    }
+  }
+  return NULL;
 }
 
-static void
-qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+static GNode *
+qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
 {
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  creation time: %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  GST_LOG ("%*s  modify time:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 16));
-  GST_LOG ("%*s  track ID:      %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 20));
-  GST_LOG ("%*s  duration:      %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 28));
-  GST_LOG ("%*s  layer:         %u", depth, "",
-      QTDEMUX_GUINT16_GET (buffer + 36));
-  GST_LOG ("%*s  alt group:     %u", depth, "",
-      QTDEMUX_GUINT16_GET (buffer + 38));
-  GST_LOG ("%*s  volume:        %g", depth, "", QTDEMUX_FP16_GET (buffer + 44));
-  GST_LOG ("%*s  track width:   %g", depth, "", QTDEMUX_FP32_GET (buffer + 84));
-  GST_LOG ("%*s  track height:  %g", depth, "", QTDEMUX_FP32_GET (buffer + 88));
+  GNode *child;
+  guint8 *buffer;
+  guint32 child_fourcc;
 
-}
+  for (child = g_node_next_sibling (node); child;
+      child = g_node_next_sibling (child)) {
+    buffer = (guint8 *) child->data;
 
-static void
-qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
+    child_fourcc = QT_FOURCC (buffer + 4);
 
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    track dur:     %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + 16 + i * 12));
-    GST_LOG ("%*s    media time:    %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + 20 + i * 12));
-    GST_LOG ("%*s    media rate:    %g", depth, "",
-        QTDEMUX_FP32_GET (buffer + 24 + i * 12));
+    if (child_fourcc == fourcc) {
+      return child;
+    }
   }
+  return NULL;
 }
 
-static void
-qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+static gboolean
+gst_qtdemux_add_stream (GstQTDemux * qtdemux,
+    QtDemuxStream * stream, GstTagList * list)
 {
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  creation time: %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  GST_LOG ("%*s  modify time:   %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 16));
-  GST_LOG ("%*s  time scale:    1/%u sec", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 20));
-  GST_LOG ("%*s  duration:      %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 24));
-  GST_LOG ("%*s  language:      %u", depth, "",
-      QTDEMUX_GUINT16_GET (buffer + 28));
-  GST_LOG ("%*s  quality:       %u", depth, "",
-      QTDEMUX_GUINT16_GET (buffer + 30));
+  if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
+    goto too_many_streams;
 
-}
+  if (stream->subtype == FOURCC_vide) {
+    gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
 
-static void
-qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  type:          %" GST_FOURCC_FORMAT, depth, "",
-      GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 12)));
-  GST_LOG ("%*s  subtype:       %" GST_FOURCC_FORMAT, depth, "",
-      GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 16)));
-  GST_LOG ("%*s  manufacturer:  %" GST_FOURCC_FORMAT, depth, "",
-      GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 20)));
-  GST_LOG ("%*s  flags:         %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 24));
-  GST_LOG ("%*s  flags mask:    %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 28));
-  GST_LOG ("%*s  name:          %*s", depth, "",
-      QTDEMUX_GUINT8_GET (buffer + 32), (char *) (buffer + 33));
+    stream->pad =
+        gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
+    g_free (name);
 
-}
+    /* fps is calculated base on the duration of the first frames since
+     * qt does not have a fixed framerate. */
+    if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
+      /* still frame */
+      stream->fps_n = 0;
+      stream->fps_d = 1;
+    } else {
+      stream->fps_n = stream->timescale;
+      if (stream->min_duration == 0)
+        stream->fps_d = 1;
+      else
+        stream->fps_d = stream->min_duration;
+    }
 
-static void
-qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  mode/color:    %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 16));
-}
+    if (stream->caps) {
+      gboolean gray;
+      gint depth, palette_count;
+      const guint32 *palette_data = NULL;
 
-static void
-qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int n;
-  int i;
-  int offset;
+      gst_caps_set_simple (stream->caps,
+          "width", G_TYPE_INT, stream->width,
+          "height", G_TYPE_INT, stream->height,
+          "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
 
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %u", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    size:          %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-    GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
-        GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
-    offset += QTDEMUX_GUINT32_GET (buffer + offset);
-  }
-}
-
-static void
-qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    size:          %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-    GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
-        GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 4)));
-    GST_LOG ("%*s    data reference:%d", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 14));
-
-    GST_LOG ("%*s    version/rev.:  %08x", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 16));
-    GST_LOG ("%*s    vendor:        %" GST_FOURCC_FORMAT, depth, "",
-        GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + offset + 20)));
-    GST_LOG ("%*s    temporal qual: %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 24));
-    GST_LOG ("%*s    spatial qual:  %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 28));
-    GST_LOG ("%*s    width:         %u", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 32));
-    GST_LOG ("%*s    height:        %u", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 34));
-    GST_LOG ("%*s    horiz. resol:  %g", depth, "",
-        QTDEMUX_FP32_GET (buffer + offset + 36));
-    GST_LOG ("%*s    vert. resol.:  %g", depth, "",
-        QTDEMUX_FP32_GET (buffer + offset + 40));
-    GST_LOG ("%*s    data size:     %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 44));
-    GST_LOG ("%*s    frame count:   %u", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 48));
-    GST_LOG ("%*s    compressor:    %d %d %d", depth, "",
-        QTDEMUX_GUINT8_GET (buffer + offset + 49),
-        QTDEMUX_GUINT8_GET (buffer + offset + 50),
-        QTDEMUX_GUINT8_GET (buffer + offset + 51));
-    //(char *) (buffer + offset + 51));
-    GST_LOG ("%*s    depth:         %u", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 82));
-    GST_LOG ("%*s    color table ID:%u", depth, "",
-        QTDEMUX_GUINT16_GET (buffer + offset + 84));
-
-    offset += QTDEMUX_GUINT32_GET (buffer + offset);
-  }
-}
-
-static void
-qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    count:         %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-    GST_LOG ("%*s    duration:      %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 4));
-
-    offset += 8;
-  }
-}
-
-static void
-qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    sample:        %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-
-    offset += 4;
-  }
-}
-
-static void
-qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    first chunk:   %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-    GST_LOG ("%*s    sample per ch: %u", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 4));
-    GST_LOG ("%*s    sample desc id:%08x", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset + 8));
-
-    offset += 12;
-  }
-}
-
-static void
-qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  //int i;
-  int n;
-  int offset;
-  int sample_size;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  sample_size = QTDEMUX_GUINT32_GET (buffer + 12);
-  GST_LOG ("%*s  sample size:   %d", depth, "", sample_size);
-  if (sample_size == 0) {
-    GST_LOG ("%*s  n entries:     %d", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + 16));
-    n = QTDEMUX_GUINT32_GET (buffer + 16);
-    offset = 20;
-#if 0
-    for (i = 0; i < n; i++) {
-      GST_LOG ("%*s    sample size:   %u", depth, "",
-          QTDEMUX_GUINT32_GET (buffer + offset));
-
-      offset += 4;
-    }
-#endif
-  }
-}
-
-static void
-qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  GST_LOG ("%*s  n entries:     %d", depth, "", n);
-  offset = 16;
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    chunk offset:  %d", depth, "",
-        QTDEMUX_GUINT32_GET (buffer + offset));
-
-    offset += 4;
-  }
-}
-
-static void
-qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  //int i;
-  int n;
-  int offset;
-
-  GST_LOG ("%*s  version/flags: %08x", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 8));
-  GST_LOG ("%*s  n entries:     %d", depth, "",
-      QTDEMUX_GUINT32_GET (buffer + 12));
-  n = QTDEMUX_GUINT32_GET (buffer + 12);
-  offset = 16;
-#if 0
-  for (i = 0; i < n; i++) {
-    GST_LOG ("%*s    chunk offset:  %" G_GUINT64_FORMAT, depth, "",
-        QTDEMUX_GUINT64_GET (buffer + offset));
-
-    offset += 8;
-  }
-#endif
-}
-
-static void
-qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  GST_LOG ("%*s  compression type: %" GST_FOURCC_FORMAT, depth, "",
-      GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (buffer + 8)));
-}
-
-static void
-qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 8));
-}
-
-static void
-qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer, int depth)
-{
-  int len;
-
-  GST_LOG ("%*s  length: %d", depth, "", QTDEMUX_GUINT32_GET (buffer + 0));
-
-  len = QTDEMUX_GUINT32_GET (buffer + 0);
-  qtdemux_dump_mem (buffer, len);
-
-}
-
-
-static GNode *
-qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
-{
-  GNode *child;
-  guint8 *buffer;
-  guint32 child_fourcc;
-
-  for (child = g_node_first_child (node); child;
-      child = g_node_next_sibling (child)) {
-    buffer = (guint8 *) child->data;
-
-    child_fourcc = GST_READ_UINT32_LE (buffer);
-    GST_LOG ("First chunk of buffer %p is [%" GST_FOURCC_FORMAT "]",
-        buffer, GST_FOURCC_ARGS (child_fourcc));
-
-    child_fourcc = GST_READ_UINT32_LE (buffer + 4);
-    GST_LOG ("buffer %p has fourcc [%" GST_FOURCC_FORMAT "]",
-        buffer, GST_FOURCC_ARGS (child_fourcc));
-
-    if (child_fourcc == fourcc) {
-      return child;
-    }
-  }
-  return NULL;
-}
-
-static GNode *
-qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
-{
-  GNode *child;
-  guint8 *buffer;
-  guint32 child_fourcc;
-
-  for (child = g_node_next_sibling (node); child;
-      child = g_node_next_sibling (child)) {
-    buffer = (guint8 *) child->data;
-
-    child_fourcc = GST_READ_UINT32_LE (buffer + 4);
-
-    if (child_fourcc == fourcc) {
-      return child;
-    }
-  }
-  return NULL;
-}
-
-static void
-gst_qtdemux_add_stream (GstQTDemux * qtdemux,
-    QtDemuxStream * stream, GstTagList * list)
-{
-  if (stream->subtype == FOURCC_vide) {
-    gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
-
-    stream->pad =
-        gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
-    g_free (name);
-
-    /* fps is calculated base on the duration of the first frames since
-     * qt does not have a fixed framerate. */
-    if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
-      /* still frame */
-      stream->fps_n = 0;
-      stream->fps_d = 1;
-    } else {
-      stream->fps_n = stream->timescale;
-      if (stream->min_duration == 0)
-        stream->fps_d = 1;
-      else
-        stream->fps_d = stream->min_duration;
-    }
-
-    if (stream->caps) {
-      gboolean gray;
-      gint depth, palette_count;
-
-      gst_caps_set_simple (stream->caps,
-          "width", G_TYPE_INT, stream->width,
-          "height", G_TYPE_INT, stream->height,
-          "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
-
-      depth = stream->bits_per_sample;
+      depth = stream->bits_per_sample;
 
       /* more than 32 bits means grayscale */
       gray = (depth > 32);
@@ -2981,21 +2149,42 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux,
       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
         palette_count = (1 << depth);
 
-      if (palette_count == 256) {
-        const guint32 *palette_data;
+      switch (palette_count) {
+        case 0:
+          break;
+        case 2:
+          palette_data = ff_qt_default_palette_2;
+          break;
+        case 4:
+          palette_data = ff_qt_default_palette_4;
+          break;
+        case 16:
+          if (gray)
+            palette_data = ff_qt_grayscale_palette_16;
+          else
+            palette_data = ff_qt_default_palette_16;
+          break;
+        case 256:
+          if (gray)
+            palette_data = ff_qt_grayscale_palette_256;
+          else
+            palette_data = ff_qt_default_palette_256;
+          break;
+        default:
+          GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
+              (_("The video in this file might not play correctly.")),
+              ("unsupported palette depth %d", depth));
+          break;
+      }
+      if (palette_data) {
         GstBuffer *palette;
 
-        if (gray)
-          palette_data = ff_qt_grayscale_palette_256;
-        else
-          palette_data = ff_qt_default_palette_256;
-
         /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
          * don't free any of the buffer data. */
         palette = gst_buffer_new ();
         GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
         GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
-        GST_BUFFER_SIZE (palette) = sizeof (guint32) * 256;
+        GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
 
         gst_caps_set_simple (stream->caps, "palette_data",
             GST_TYPE_BUFFER, palette, NULL);
@@ -3025,7 +2214,7 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux,
     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
   } else {
     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
-    return;
+    goto done;
   }
 
   qtdemux->streams[qtdemux->n_streams] = stream;
@@ -3052,282 +2241,402 @@ gst_qtdemux_add_stream (GstQTDemux * qtdemux,
       gst_element_found_tags_for_pad (GST_ELEMENT_CAST (qtdemux), stream->pad,
           list);
   }
-}
-
-static void qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak);
-
-typedef struct
-{
-  GstStructure *structure;      /* helper for sort function */
-  gchar *location;
-  guint min_req_bitrate;
-  guint min_req_qt_version;
-} GstQtReference;
-
-static gint
-qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
-{
-  GstQtReference *ref_a = (GstQtReference *) a;
-  GstQtReference *ref_b = (GstQtReference *) b;
-
-  if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
-    return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
+done:
+  return TRUE;
 
-  /* known bitrates go before unknown; higher bitrates go first */
-  return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
+too_many_streams:
+  {
+    GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
+        (_("This file contains too many streams. Only playing first %d"),
+            GST_QTDEMUX_MAX_STREAMS), (NULL));
+    return TRUE;
+  }
 }
 
-static void
-qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
+/* collect all samples for @stream by reading the info from @stbl
+ */
+static gboolean
+qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GNode * stbl)
 {
-  GstQtReference *best;
-  GstStructure *s;
-  GstMessage *msg;
-  GValue list_val = { 0, };
-  GList *l;
+  int offset;
+  GNode *stsc;
+  GNode *stsz;
+  GNode *stco;
+  GNode *co64;
+  GNode *stts;
+  GNode *stss;
+  const guint8 *stsc_data, *stsz_data, *stco_data;
+  int sample_size;
+  int sample_index;
+  int n_samples;
+  int n_samples_per_chunk;
+  int n_sample_times;
+  QtDemuxSample *samples;
+  gint i, j, k;
+  int index;
+  guint64 timestamp, time;
 
-  g_assert (references != NULL);
+  /* sample to chunk */
+  if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
+    goto corrupt_file;
+  stsc_data = (const guint8 *) stsc->data;
+  /* sample size */
+  if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
+    goto corrupt_file;
+  stsz_data = (const guint8 *) stsz->data;
+  /* chunk offsets */
+  stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
+  co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
+  if (stco) {
+    stco_data = (const guint8 *) stco->data;
+  } else {
+    stco_data = NULL;
+    if (co64 == NULL)
+      goto corrupt_file;
+  }
+  /* sample time */
+  if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts)))
+    goto corrupt_file;
 
-  references = g_list_sort (references, qtdemux_redirects_sort_func);
+  /* sample sync, can be NULL */
+  stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
 
-  best = (GstQtReference *) references->data;
+  sample_size = QT_UINT32 (stsz_data + 12);
+  if (sample_size == 0 || stream->sampled) {
+    n_samples = QT_UINT32 (stsz_data + 16);
+    GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
+        n_samples);
+    stream->n_samples = n_samples;
+    samples = g_new0 (QtDemuxSample, n_samples);
+    stream->samples = samples;
 
-  g_value_init (&list_val, GST_TYPE_LIST);
+    for (i = 0; i < n_samples; i++) {
+      if (sample_size == 0)
+        samples[i].size = QT_UINT32 (stsz_data + i * 4 + 20);
+      else
+        samples[i].size = sample_size;
 
-  for (l = references; l != NULL; l = l->next) {
-    GstQtReference *ref = (GstQtReference *) l->data;
-    GValue struct_val = { 0, };
-
-    ref->structure = gst_structure_new ("redirect",
-        "new-location", G_TYPE_STRING, ref->location, NULL);
-
-    if (ref->min_req_bitrate > 0) {
-      gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
-          ref->min_req_bitrate, NULL);
+      GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
+      /* init other fields to defaults for this sample */
+      samples[i].keyframe = FALSE;
     }
+    n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
+    index = 0;
+    for (i = 0; i < n_samples_per_chunk; i++) {
+      guint32 first_chunk, last_chunk;
+      guint32 samples_per_chunk;
 
-    g_value_init (&struct_val, GST_TYPE_STRUCTURE);
-    g_value_set_boxed (&struct_val, ref->structure);
-    gst_value_list_append_value (&list_val, &struct_val);
-    g_value_unset (&struct_val);
-    /* don't free anything here yet, since we need best->structure below */
-  }
-
-  g_assert (best != NULL);
-  s = gst_structure_copy (best->structure);
-
-  if (g_list_length (references) > 1) {
-    gst_structure_set_value (s, "locations", &list_val);
-  }
-
-  g_value_unset (&list_val);
-
-  for (l = references; l != NULL; l = l->next) {
-    GstQtReference *ref = (GstQtReference *) l->data;
+      first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
+      if (i == n_samples_per_chunk - 1) {
+        last_chunk = G_MAXUINT32;
+      } else {
+        last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
+      }
+      samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
 
-    gst_structure_free (ref->structure);
-    g_free (ref->location);
-    g_free (ref);
-  }
-  g_list_free (references);
+      for (j = first_chunk; j < last_chunk; j++) {
+        guint64 chunk_offset;
 
-  GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
-  msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
-  gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
-}
+        if (stco) {
+          chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
+        } else {
+          chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
+        }
+        for (k = 0; k < samples_per_chunk; k++) {
+          GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
+              index, chunk_offset);
+          samples[index].chunk = j;
+          samples[index].offset = chunk_offset;
+          chunk_offset += samples[index].size;
+          index++;
+          if (index >= n_samples)
+            goto done2;
+        }
+      }
+    }
+  done2:
 
-static void
-qtdemux_parse_tree (GstQTDemux * qtdemux)
-{
-  GNode *mvhd;
-  GNode *trak;
-  GNode *udta;
+    n_sample_times = QT_UINT32 ((guint8 *) stts->data + 12);
+    timestamp = 0;
+    stream->min_duration = 0;
+    time = 0;
+    index = 0;
+    for (i = 0; i < n_sample_times; i++) {
+      guint32 n;
+      guint32 duration;
 
-  mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
-  if (mvhd == NULL) {
-    GNode *rmra, *rmda, *rdrf;
-
-    rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
-    if (rmra) {
-      GList *redirects = NULL;
-
-      rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
-      while (rmda) {
-        GstQtReference ref = { NULL, NULL, 0, 0 };
-        GNode *rmdr, *rmvc;
-
-        if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
-          ref.min_req_bitrate =
-              QTDEMUX_GUINT32_GET ((guint8 *) rmdr->data + 12);
-          GST_LOG ("data rate atom, required bitrate = %u",
-              ref.min_req_bitrate);
-        }
+      n = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i);
+      duration = QT_UINT32 ((guint8 *) stts->data + 16 + 8 * i + 4);
+      for (j = 0; j < n; j++) {
+        GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
+            index, GST_TIME_ARGS (timestamp));
 
-        if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
-          guint32 package = QTDEMUX_FOURCC_GET ((guint8 *) rmvc->data + 12);
-          guint version = QTDEMUX_GUINT32_GET ((guint8 *) rmvc->data + 16);
+        samples[index].timestamp = timestamp;
+        /* take first duration for fps */
+        if (stream->min_duration == 0)
+          stream->min_duration = duration;
+        /* add non-scaled values to avoid rounding errors */
+        time += duration;
+        timestamp = gst_util_uint64_scale_int (time,
+            GST_SECOND, stream->timescale);
+        samples[index].duration = timestamp - samples[index].timestamp;
 
-#ifndef GST_DISABLE_GST_DEBUG
-          guint bitmask = QTDEMUX_GUINT32_GET ((guint8 *) rmvc->data + 20);
-#endif
-          guint check_type = QTDEMUX_GUINT16_GET ((guint8 *) rmvc->data + 24);
+        index++;
+      }
+    }
+    if (stss) {
+      /* mark keyframes */
+      guint32 n_sample_syncs;
 
-          GST_LOG ("version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
-              ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
-              bitmask, check_type);
-          if (package == FOURCC_qtim && check_type == 0) {
-            ref.min_req_qt_version = version;
-          }
+      n_sample_syncs = QT_UINT32 ((guint8 *) stss->data + 12);
+      if (n_sample_syncs == 0) {
+        stream->all_keyframe = TRUE;
+      } else {
+        offset = 16;
+        for (i = 0; i < n_sample_syncs; i++) {
+          /* note that the first sample is index 1, not 0 */
+          index = QT_UINT32 ((guint8 *) stss->data + offset);
+          samples[index - 1].keyframe = TRUE;
+          offset += 4;
         }
+      }
+    } else {
+      /* no stss, all samples are keyframes */
+      stream->all_keyframe = TRUE;
+    }
+  } else {
+    GST_DEBUG_OBJECT (qtdemux,
+        "stsz sample_size %d != 0, treating chunks as samples", sample_size);
 
-        rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
-        if (rdrf) {
-          guint32 ref_type;
-          guint8 *ref_data;
-
-          ref_type = GST_READ_UINT32_LE ((guint8 *) rdrf->data + 12);
-          ref_data = (guint8 *) rdrf->data + 20;
-          if (ref_type == GST_MAKE_FOURCC ('a', 'l', 'i', 's')) {
-            guint record_len, record_version, fn_len;
-
-            /* MacOSX alias record, google for alias-layout.txt */
-            record_len = GST_READ_UINT16_BE (ref_data + 4);
-            record_version = GST_READ_UINT16_BE (ref_data + 4 + 2);
-            fn_len = GST_READ_UINT8 (ref_data + 50);
-            if (record_len > 50 && record_version == 2 && fn_len > 0) {
-              ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
-            }
-          } else if (ref_type == GST_MAKE_FOURCC ('u', 'r', 'l', ' ')) {
-            ref.location = g_strdup ((gchar *) ref_data);
-          } else {
-            GST_DEBUG ("unknown rdrf reference type %" GST_FOURCC_FORMAT,
-                GST_FOURCC_ARGS (ref_type));
-          }
-          if (ref.location != NULL) {
-            GST_INFO ("New location: %s", ref.location);
-            redirects =
-                g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
-          } else {
-            GST_WARNING ("Failed to extract redirect location from rdrf atom");
-          }
-        }
+    /* treat chunks as samples */
+    if (stco) {
+      n_samples = QT_UINT32 (stco_data + 12);
+    } else {
+      n_samples = QT_UINT32 ((guint8 *) co64->data + 12);
+    }
+    stream->n_samples = n_samples;
+    GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
+    samples = g_new0 (QtDemuxSample, n_samples);
+    stream->samples = samples;
 
-        /* look for others */
-        rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
-      }
+    n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
+    GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
+    sample_index = 0;
+    timestamp = 0;
+    for (i = 0; i < n_samples_per_chunk; i++) {
+      guint32 first_chunk, last_chunk;
+      guint32 samples_per_chunk;
 
-      if (redirects != NULL) {
-        qtdemux_process_redirects (qtdemux, redirects);
-        return;
+      first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
+      /* the last chunk of each entry is calculated by taking the first chunk
+       * of the next entry; except if there is no next, where we fake it with
+       * INT_MAX */
+      if (i == n_samples_per_chunk - 1) {
+        last_chunk = G_MAXUINT32;
+      } else {
+        last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
       }
-    }
+      samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
 
-    GST_LOG ("No mvhd node found.");
-    return;
-  }
+      GST_LOG_OBJECT (qtdemux,
+          "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
+          first_chunk, last_chunk, samples_per_chunk);
 
-  qtdemux->timescale = QTDEMUX_GUINT32_GET ((guint8 *) mvhd->data + 20);
-  qtdemux->duration = QTDEMUX_GUINT32_GET ((guint8 *) mvhd->data + 24);
+      for (j = first_chunk; j < last_chunk; j++) {
+        guint64 chunk_offset;
 
-  GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
-  GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
+        if (j >= n_samples)
+          goto done;
 
-  if (TRUE) {
-    gint64 duration;
+        if (stco) {
+          chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
+        } else {
+          chunk_offset = QT_UINT64 ((guint8 *) co64->data + 16 + j * 8);
+        }
+        GST_LOG_OBJECT (qtdemux,
+            "Creating entry %d with offset %" G_GUINT64_FORMAT, j,
+            chunk_offset);
 
-    gst_qtdemux_get_duration (qtdemux, &duration);
-    gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
-  }
+        samples[j].chunk = j;
+        samples[j].offset = chunk_offset;
 
-  trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
-  qtdemux_parse_trak (qtdemux, trak);
+        if (stream->samples_per_frame * stream->bytes_per_frame) {
+          samples[j].size = (samples_per_chunk * stream->n_channels) /
+              stream->samples_per_frame * stream->bytes_per_frame;
+        } else {
+          samples[j].size = samples_per_chunk;
+        }
 
-  /* kid pads */
-  while ((trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak)))
-    qtdemux_parse_trak (qtdemux, trak);
+        GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
+            ", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size);
 
-  gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
+        samples[j].timestamp = timestamp;
+        sample_index += samples_per_chunk;
 
-  /* tags */
-  udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
-  if (udta) {
-    qtdemux_parse_udta (qtdemux, udta);
+        timestamp = gst_util_uint64_scale_int (sample_index,
+            GST_SECOND, stream->timescale);
+        samples[j].duration = timestamp - samples[j].timestamp;
 
-    if (qtdemux->tag_list) {
-      GST_DEBUG_OBJECT (qtdemux,
-          "calling gst_element_found_tags with %" GST_PTR_FORMAT,
-          qtdemux->tag_list);
-      gst_element_found_tags (GST_ELEMENT_CAST (qtdemux), qtdemux->tag_list);
-      qtdemux->tag_list = NULL;
+        samples[j].keyframe = TRUE;
+      }
     }
-  } else {
-    GST_LOG ("No udta node found.");
+  }
+done:
+  return TRUE;
+
+/* ERRORS */
+corrupt_file:
+  {
+    GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
+        (_("This file is corrupt and cannot be played.")), (NULL));
+    return FALSE;
   }
 }
 
-static void
-qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
+/* collect all segment info for @stream.
+ */
+static gboolean
+qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
+    GNode * trak)
 {
-  int offset;
-  GNode *tkhd;
-  GNode *mdia;
-  GNode *mdhd;
-  GNode *hdlr;
-  GNode *minf;
-  GNode *stbl;
-  GNode *stsd;
-  GNode *stsc;
-  GNode *stss;
-  GNode *stsz;
-  GNode *stco;
-  GNode *co64;
-  GNode *stts;
-  GNode *mp4a;
-  GNode *mp4v;
-  GNode *wave;
-  GNode *esds;
   GNode *edts;
-  int n_samples;
-  QtDemuxSample *samples;
-  int n_samples_per_chunk;
-  int index;
-  int i, j, k;
-  QtDemuxStream *stream;
-  int n_sample_times;
-  guint64 timestamp, time;
-  int sample_size;
-  int sample_index;
-  GstTagList *list = NULL;
-  const gchar *codec = NULL;
-  const guint8 *stsd_data, *stsc_data, *stsz_data, *stco_data;
 
-  tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd);
-  g_return_if_fail (tkhd);
-
-  GST_LOG ("track[tkhd] version/flags: 0x%08x",
-      QTDEMUX_GUINT32_GET ((guint8 *) tkhd->data + 8));
+  /* parse and prepare segment info from the edit list */
+  GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
+  stream->n_segments = 0;
+  stream->segments = NULL;
+  if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
+    GNode *elst;
+    gint n_segments;
+    gint i, count;
+    guint64 time, stime;
+    guint8 *buffer;
 
-  mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia);
-  if (mdia == NULL)
-    goto corrupt_file;
+    GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
+    if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
+      goto done;
 
-  mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd);
-  if (mdhd == NULL)
-    goto corrupt_file;
+    buffer = elst->data;
 
-  /* new streams always need a discont */
-  stream = g_new0 (QtDemuxStream, 1);
-  stream->discont = TRUE;
-  stream->segment_index = -1;
-  stream->time_position = 0;
-  stream->sample_index = 0;
-  stream->last_ret = GST_FLOW_OK;
+    n_segments = QT_UINT32 (buffer + 12);
 
-  stream->timescale = QTDEMUX_GUINT32_GET ((guint8 *) mdhd->data + 20);
-  stream->duration = QTDEMUX_GUINT32_GET ((guint8 *) mdhd->data + 24);
+    /* we might allocate a bit too much, at least allocate 1 segment */
+    stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
 
-  GST_LOG ("track timescale: %d", stream->timescale);
-  GST_LOG ("track duration: %d", stream->duration);
+    /* segments always start from 0 */
+    time = 0;
+    stime = 0;
+    count = 0;
+    for (i = 0; i < n_segments; i++) {
+      guint64 duration;
+      guint64 media_time;
+      QtDemuxSegment *segment;
+
+      media_time = QT_UINT32 (buffer + 20 + i * 12);
+
+      /* -1 media time is an empty segment, just ignore it */
+      if (media_time == G_MAXUINT32)
+        continue;
+
+      duration = QT_UINT32 (buffer + 16 + i * 12);
+
+      segment = &stream->segments[count++];
+
+      /* time and duration expressed in global timescale */
+      segment->time = stime;
+      /* add non scaled values so we don't cause roundoff errors */
+      time += duration;
+      stime = gst_util_uint64_scale_int (time, GST_SECOND, qtdemux->timescale);
+      segment->stop_time = stime;
+      segment->duration = stime - segment->time;
+      /* media_time expressed in stream timescale */
+      segment->media_start =
+          gst_util_uint64_scale_int (media_time, GST_SECOND, stream->timescale);
+      segment->media_stop = segment->media_start + segment->duration;
+      segment->rate = QT_FP32 (buffer + 24 + i * 12);
+
+      GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
+          ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
+          ", rate %g", i, GST_TIME_ARGS (segment->time),
+          GST_TIME_ARGS (segment->duration),
+          GST_TIME_ARGS (segment->media_start), segment->rate);
+    }
+    GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
+    stream->n_segments = count;
+  }
+done:
+
+  /* no segments, create one to play the complete trak */
+  if (stream->n_segments == 0) {
+    if (stream->segments == NULL)
+      stream->segments = g_new (QtDemuxSegment, 1);
+
+    stream->segments[0].time = 0;
+    stream->segments[0].stop_time = qtdemux->segment.duration;
+    stream->segments[0].duration = qtdemux->segment.duration;
+    stream->segments[0].media_start = 0;
+    stream->segments[0].media_stop = qtdemux->segment.duration;
+    stream->segments[0].rate = 1.0;
+
+    GST_DEBUG_OBJECT (qtdemux, "created dummy segment");
+    stream->n_segments = 1;
+  }
+  GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
+
+  return TRUE;
+}
+
+/* parse the traks.
+ * With each track we associate a new QtDemuxStream that contains all the info
+ * about the trak. 
+ * traks that do not decode to something (like strm traks) will not have a pad.
+ */
+static gboolean
+qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
+{
+  int offset;
+  GNode *tkhd;
+  GNode *mdia;
+  GNode *mdhd;
+  GNode *hdlr;
+  GNode *minf;
+  GNode *stbl;
+  GNode *stsd;
+  GNode *mp4a;
+  GNode *mp4v;
+  GNode *wave;
+  GNode *esds;
+  QtDemuxStream *stream;
+  GstTagList *list = NULL;
+  const gchar *codec = NULL;
+  const guint8 *stsd_data;
+
+  /* new streams always need a discont */
+  stream = g_new0 (QtDemuxStream, 1);
+  stream->discont = TRUE;
+  stream->segment_index = -1;
+  stream->time_position = 0;
+  stream->sample_index = 0;
+  stream->last_ret = GST_FLOW_OK;
+
+  if (!(tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd)))
+    goto corrupt_file;
+
+  GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%08x",
+      QT_UINT32 ((guint8 *) tkhd->data + 8));
+
+  if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
+    goto corrupt_file;
+
+  if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd)))
+    goto corrupt_file;
+
+  stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
+  stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
+
+  GST_LOG_OBJECT (qtdemux, "track timescale: %d", stream->timescale);
+  GST_LOG_OBJECT (qtdemux, "track duration: %d", stream->duration);
 
   if (qtdemux->duration != G_MAXINT32 && stream->duration != G_MAXINT32) {
     guint64 tdur1, tdur2;
@@ -3341,36 +2650,34 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
      * themselves vide tracks as well. I haven't really found a way to
      * identify those yet, except for just looking at their duration. */
     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
-      GST_WARNING ("Track shorter than 20%% (%d/%d vs. %d/%d) of the stream "
+      GST_WARNING_OBJECT (qtdemux,
+          "Track shorter than 20%% (%d/%d vs. %d/%d) of the stream "
           "found, assuming preview image or something; skipping track",
           stream->duration, stream->timescale, qtdemux->duration,
           qtdemux->timescale);
       g_free (stream);
-      return;
+      return TRUE;
     }
   }
 
-  hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr);
-  if (hdlr == NULL)
+  if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
     goto corrupt_file;
 
-  GST_LOG ("track type: %" GST_FOURCC_FORMAT,
-      GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET ((guint8 *) hdlr->data + 12)));
+  GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
 
-  stream->subtype = QTDEMUX_FOURCC_GET ((guint8 *) hdlr->data + 16);
-  GST_LOG ("track subtype: %" GST_FOURCC_FORMAT,
+  stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
+  GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
       GST_FOURCC_ARGS (stream->subtype));
 
-  minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf);
-  if (minf == NULL)
+  if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
     goto corrupt_file;
 
-  stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl);
-  if (stbl == NULL)
+  if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
     goto corrupt_file;
 
-  stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd);
-  if (stsd == NULL)
+  /* parse stsd */
+  if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
     goto corrupt_file;
   stsd_data = (const guint8 *) stsd->data;
 
@@ -3380,21 +2687,21 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
     stream->sampled = TRUE;
 
     offset = 16;
-    stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd_data + offset + 4);
-
-    GST_LOG ("st type:          %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
+    stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4);
+    GST_LOG_OBJECT (qtdemux, "st type:          %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (fourcc));
 
-    stream->width = QTDEMUX_GUINT16_GET (stsd_data + offset + 32);
-    stream->height = QTDEMUX_GUINT16_GET (stsd_data + offset + 34);
+    stream->width = QT_UINT16 (stsd_data + offset + 32);
+    stream->height = QT_UINT16 (stsd_data + offset + 34);
     stream->fps_n = 0;          /* this is filled in later */
     stream->fps_d = 0;          /* this is filled in later */
-    stream->bits_per_sample = QTDEMUX_GUINT16_GET (stsd_data + offset + 82);
-    stream->color_table_id = QTDEMUX_GUINT16_GET (stsd_data + offset + 84);
+    stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
+    stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
 
-    GST_LOG ("frame count:   %u",
-        QTDEMUX_GUINT16_GET (stsd_data + offset + 48));
+    GST_LOG_OBJECT (qtdemux, "frame count:   %u",
+        QT_UINT16 (stsd_data + offset + 48));
 
-    if (fourcc == GST_MAKE_FOURCC ('d', 'r', 'm', 's'))
+    if (fourcc == FOURCC_drms)
       goto error_encrypted;
 
     stream->caps = qtdemux_video_caps (qtdemux, fourcc, stsd_data, &codec);
@@ -3412,100 +2719,100 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
     if (esds) {
       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
     } else {
-      if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('a', 'v', 'c', '1')) {
-        gint len = QTDEMUX_GUINT32_GET (stsd_data) - 0x66;
-        const guint8 *avc_data = stsd_data + 0x66;
-
-        /* find avcC */
-        while (len >= 0x8 &&
-            QTDEMUX_FOURCC_GET (avc_data + 0x4) !=
-            GST_MAKE_FOURCC ('a', 'v', 'c', 'C') &&
-            QTDEMUX_GUINT32_GET (avc_data) < len) {
-          len -= QTDEMUX_GUINT32_GET (avc_data);
-          avc_data += QTDEMUX_GUINT32_GET (avc_data);
-        }
+      switch (fourcc) {
+        case FOURCC_avc1:
+        {
+          gint len = QT_UINT32 (stsd_data) - 0x66;
+          const guint8 *avc_data = stsd_data + 0x66;
+
+          /* find avcC */
+          while (len >= 0x8 &&
+              QT_FOURCC (avc_data + 0x4) != FOURCC_avcC &&
+              QT_UINT32 (avc_data) < len) {
+            len -= QT_UINT32 (avc_data);
+            avc_data += QT_UINT32 (avc_data);
+          }
 
-        /* parse, if found */
-        if (len > 0x8 &&
-            QTDEMUX_FOURCC_GET (avc_data + 0x4) ==
-            GST_MAKE_FOURCC ('a', 'v', 'c', 'C')) {
+          /* parse, if found */
+          if (len > 0x8 && QT_FOURCC (avc_data + 0x4) == FOURCC_avcC) {
+            GstBuffer *buf;
+            gint size;
+
+            if (QT_UINT32 (avc_data) < len)
+              size = QT_UINT32 (avc_data) - 0x8;
+            else
+              size = len - 0x8;
+
+            GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
+
+            buf = gst_buffer_new_and_alloc (size);
+            memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
+            gst_caps_set_simple (stream->caps,
+                "codec_data", GST_TYPE_BUFFER, buf, NULL);
+            gst_buffer_unref (buf);
+          }
+          break;
+        }
+        case FOURCC_SVQ3:
+        case FOURCC_VP31:
+        {
           GstBuffer *buf;
-          gint size;
+          gint len = QT_UINT32 (stsd_data);
 
-          if (QTDEMUX_GUINT32_GET (avc_data) < len)
-            size = QTDEMUX_GUINT32_GET (avc_data) - 0x8;
-          else
-            size = len - 0x8;
+          GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
 
-          buf = gst_buffer_new_and_alloc (size);
-          memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
+          buf = gst_buffer_new_and_alloc (len);
+          memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
           gst_caps_set_simple (stream->caps,
               "codec_data", GST_TYPE_BUFFER, buf, NULL);
           gst_buffer_unref (buf);
+          break;
+        }
+        case FOURCC_rle_:
+        {
+          gst_caps_set_simple (stream->caps,
+              "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
+          break;
         }
-      } else if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('S', 'V', 'Q', '3')) {
-        GstBuffer *buf;
-        gint len = QTDEMUX_GUINT32_GET (stsd_data);
-
-        buf = gst_buffer_new_and_alloc (len);
-        memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
-        gst_caps_set_simple (stream->caps,
-            "codec_data", GST_TYPE_BUFFER, buf, NULL);
-        gst_buffer_unref (buf);
-      } else if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('V', 'P', '3', '1')) {
-        GstBuffer *buf;
-        gint len = QTDEMUX_GUINT32_GET (stsd_data);
-
-        buf = gst_buffer_new_and_alloc (len);
-        memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
-        gst_caps_set_simple (stream->caps,
-            "codec_data", GST_TYPE_BUFFER, buf, NULL);
-        gst_buffer_unref (buf);
-      } else if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('r', 'l', 'e', ' ')) {
-        gst_caps_set_simple (stream->caps,
-            "depth", G_TYPE_INT, QTDEMUX_GUINT16_GET (stsd_data + offset + 82),
-            NULL);
+        default:
+          break;
       }
     }
 
     GST_INFO_OBJECT (qtdemux,
         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
-        GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd_data + offset + 4)),
-        stream->caps);
+        GST_FOURCC_ARGS (fourcc), stream->caps);
+
   } else if (stream->subtype == FOURCC_soun) {
     int version, samplesize;
     guint32 fourcc;
     int len;
     guint16 compression_id;
 
-    len = QTDEMUX_GUINT32_GET (stsd_data + 16);
-    GST_LOG ("stsd len:           %d", len);
+    len = QT_UINT32 (stsd_data + 16);
+    GST_LOG_OBJECT (qtdemux, "stsd len:           %d", len);
 
-    stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd_data + 16 + 4);
-    GST_LOG ("stsd type:          %" GST_FOURCC_FORMAT,
+    stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
+    GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
         GST_FOURCC_ARGS (stream->fourcc));
 
     offset = 32;
 
-    version = QTDEMUX_GUINT32_GET (stsd_data + offset);
-    stream->n_channels = QTDEMUX_GUINT16_GET (stsd_data + offset + 8);
-    samplesize = QTDEMUX_GUINT16_GET (stsd_data + offset + 10);
-    compression_id = QTDEMUX_GUINT16_GET (stsd_data + offset + 12);
-    stream->rate = QTDEMUX_FP32_GET (stsd_data + offset + 16);
-
-    GST_LOG ("version/rev:      %08x", version);
-    GST_LOG ("vendor:           %08x",
-        QTDEMUX_GUINT32_GET (stsd_data + offset + 4));
-    GST_LOG ("n_channels:       %d", stream->n_channels);
-    GST_LOG ("sample_size:      %d", samplesize);
-    GST_LOG ("compression_id:   %d", compression_id);
-    GST_LOG ("packet size:      %d",
-        QTDEMUX_GUINT16_GET (stsd_data + offset + 14));
-    GST_LOG ("sample rate:      %g", stream->rate);
+    version = QT_UINT32 (stsd_data + offset);
+    stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
+    samplesize = QT_UINT16 (stsd_data + offset + 10);
+    compression_id = QT_UINT16 (stsd_data + offset + 12);
+    stream->rate = QT_FP32 (stsd_data + offset + 16);
+
+    GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
+    GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
+        QT_UINT32 (stsd_data + offset + 4));
+    GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
+    GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
+    GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
+    GST_LOG_OBJECT (qtdemux, "packet size:      %d",
+        QT_UINT16 (stsd_data + offset + 14));
+    GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
 
     if (compression_id == 0xfffe)
       stream->sampled = TRUE;
@@ -3518,57 +2825,78 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
     stream->bytes_per_packet = stream->bytes_per_sample;
 
     offset = 52;
-    if (version == 0x00000000) {
-      /* Yes, these have to be hard-coded */
-      if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '6')) {
+    switch (fourcc) {
+        /* Yes, these have to be hard-coded */
+      case FOURCC_MAC6:
+      {
         stream->samples_per_packet = 6;
         stream->bytes_per_packet = 1;
         stream->bytes_per_frame = 1 * stream->n_channels;
         stream->bytes_per_sample = 1;
         stream->samples_per_frame = 6 * stream->n_channels;
+        break;
       }
-      if (fourcc == GST_MAKE_FOURCC ('M', 'A', 'C', '3')) {
+      case FOURCC_MAC3:
+      {
         stream->samples_per_packet = 3;
         stream->bytes_per_packet = 1;
         stream->bytes_per_frame = 1 * stream->n_channels;
         stream->bytes_per_sample = 1;
         stream->samples_per_frame = 3 * stream->n_channels;
+        break;
       }
-      if (fourcc == GST_MAKE_FOURCC ('i', 'm', 'a', '4')) {
+      case FOURCC_ima4:
+      {
         stream->samples_per_packet = 64;
         stream->bytes_per_packet = 34;
         stream->bytes_per_frame = 34 * stream->n_channels;
         stream->bytes_per_sample = 2;
         stream->samples_per_frame = 64 * stream->n_channels;
+        break;
       }
-      if (fourcc == GST_MAKE_FOURCC ('u', 'l', 'a', 'w') ||
-          fourcc == GST_MAKE_FOURCC ('a', 'l', 'a', 'w')) {
+      case FOURCC_ulaw:
+      case FOURCC_alaw:
+      {
         stream->samples_per_packet = 1;
         stream->bytes_per_packet = 1;
         stream->bytes_per_frame = 1 * stream->n_channels;
         stream->bytes_per_sample = 1;
         stream->samples_per_frame = 1 * stream->n_channels;
+        break;
       }
-    } else if (version == 0x00010000) {
-      if (fourcc != GST_MAKE_FOURCC ('t', 'w', 'o', 's') &&
-          fourcc != GST_MAKE_FOURCC ('s', 'o', 'w', 't') &&
-          fourcc != GST_MAKE_FOURCC ('r', 'a', 'w', ' ')) {
-        /* only parse extra decoding config for non-pcm audio */
-        stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd_data + offset);
-        stream->bytes_per_packet = QTDEMUX_GUINT32_GET (stsd_data + offset + 4);
-        stream->bytes_per_frame = QTDEMUX_GUINT32_GET (stsd_data + offset + 8);
-        stream->bytes_per_sample =
-            QTDEMUX_GUINT32_GET (stsd_data + offset + 12);
-
-        GST_LOG ("samples/packet:   %d", stream->samples_per_packet);
-        GST_LOG ("bytes/packet:     %d", stream->bytes_per_packet);
-        GST_LOG ("bytes/frame:      %d", stream->bytes_per_frame);
-        GST_LOG ("bytes/sample:     %d", stream->bytes_per_sample);
-
-        if (!stream->sampled) {
-          stream->samples_per_frame = (stream->bytes_per_frame /
-              stream->bytes_per_packet) * stream->samples_per_packet;
-          GST_LOG ("samples/frame:    %d", stream->samples_per_frame);
+      default:
+        break;
+    }
+    if (version == 0x00010000) {
+      switch (fourcc) {
+        case FOURCC_twos:
+        case FOURCC_sowt:
+        case FOURCC_raw_:
+          break;
+        default:
+        {
+          /* only parse extra decoding config for non-pcm audio */
+          stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
+          stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
+          stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
+          stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
+
+          GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
+              stream->samples_per_packet);
+          GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
+              stream->bytes_per_packet);
+          GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
+              stream->bytes_per_frame);
+          GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
+              stream->bytes_per_sample);
+
+          if (!stream->sampled && stream->bytes_per_packet) {
+            stream->samples_per_frame = (stream->bytes_per_frame /
+                stream->bytes_per_packet) * stream->samples_per_packet;
+            GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
+                stream->samples_per_frame);
+          }
+          break;
         }
       }
       offset = 68;
@@ -3579,21 +2907,22 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
         guint64 val;
       } qtfp;
 
-      stream->samples_per_packet = QTDEMUX_GUINT32_GET (stsd_data + offset);
-      qtfp.val = QTDEMUX_GUINT64_GET (stsd_data + offset + 4);
+      stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
+      qtfp.val = QT_UINT64 (stsd_data + offset + 4);
       stream->rate = qtfp.fp;
-      stream->n_channels = QTDEMUX_GUINT32_GET (stsd_data + offset + 12);
+      stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
 
-      GST_LOG ("samples/packet:   %d", stream->samples_per_packet);
-      GST_LOG ("sample rate:      %g", stream->rate);
-      GST_LOG ("n_channels:       %d", stream->n_channels);
+      GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
+          stream->samples_per_packet);
+      GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
+      GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
 
       offset = 68;
     } else {
-      GST_WARNING ("unknown version %08x", version);
+      GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
     }
 
-    if (fourcc == GST_MAKE_FOURCC ('d', 'r', 'm', 's'))
+    if (fourcc == FOURCC_drms)
       goto error_encrypted;
 
     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
@@ -3619,470 +2948,125 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
     if (esds) {
       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
     } else {
-      if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('Q', 'D', 'M', '2')) {
-        gint len = QTDEMUX_GUINT32_GET (stsd_data);
-
-        if (len > 0x4C) {
-          GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
-
-          memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
+      switch (fourcc) {
+        case FOURCC_QDM2:
+        {
+          gint len = QT_UINT32 (stsd_data);
+
+          if (len > 0x4C) {
+            GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
+
+            memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
+            gst_caps_set_simple (stream->caps,
+                "codec_data", GST_TYPE_BUFFER, buf, NULL);
+            gst_buffer_unref (buf);
+          }
           gst_caps_set_simple (stream->caps,
-              "codec_data", GST_TYPE_BUFFER, buf, NULL);
-          gst_buffer_unref (buf);
+              "samplesize", G_TYPE_INT, samplesize, NULL);
+          break;
         }
-        gst_caps_set_simple (stream->caps,
-            "samplesize", G_TYPE_INT, samplesize, NULL);
-      } else if (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4) ==
-          GST_MAKE_FOURCC ('a', 'l', 'a', 'c')) {
-        gint len = QTDEMUX_GUINT32_GET (stsd_data);
+        case FOURCC_alac:
+        {
+          gint len = QT_UINT32 (stsd_data);
 
-        if (len > 0x34) {
-          GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
+          if (len > 0x34) {
+            GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
 
-          memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
+            memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
+            gst_caps_set_simple (stream->caps,
+                "codec_data", GST_TYPE_BUFFER, buf, NULL);
+            gst_buffer_unref (buf);
+          }
           gst_caps_set_simple (stream->caps,
-              "codec_data", GST_TYPE_BUFFER, buf, NULL);
-          gst_buffer_unref (buf);
+              "samplesize", G_TYPE_INT, samplesize, NULL);
+          break;
         }
-        gst_caps_set_simple (stream->caps,
-            "samplesize", G_TYPE_INT, samplesize, NULL);
+        default:
+          break;
       }
     }
     GST_INFO_OBJECT (qtdemux,
         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
-        GST_FOURCC_ARGS (QTDEMUX_FOURCC_GET (stsd_data + 16 + 4)),
-        stream->caps);
+        GST_FOURCC_ARGS (fourcc), stream->caps);
+
   } else if (stream->subtype == FOURCC_strm) {
     guint32 fourcc;
 
-    stream->fourcc = fourcc = QTDEMUX_FOURCC_GET (stsd_data + 16 + 4);
+    stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
         GST_FOURCC_ARGS (fourcc));
 
     if (fourcc != FOURCC_rtsp) {
       GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
           GST_FOURCC_ARGS (fourcc));
-      goto unknown;
+      goto unknown_stream;
     }
     stream->sampled = TRUE;
   } else {
-  unknown:
-    GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
-        GST_FOURCC_ARGS (stream->subtype));
-    g_free (stream);
-    return;
+    goto unknown_stream;
   }
 
   /* promote to sampled format */
-  if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'm', 'r')) {
+  if (stream->fourcc == FOURCC_samr) {
     /* force mono 8000 Hz for AMR */
     stream->sampled = TRUE;
     stream->n_channels = 1;
     stream->rate = 8000;
-  } else if (stream->fourcc == GST_MAKE_FOURCC ('s', 'a', 'w', 'b')) {
+  } else if (stream->fourcc == FOURCC_sawb) {
     /* force mono 16000 Hz for AMR-WB */
     stream->sampled = TRUE;
     stream->n_channels = 1;
     stream->rate = 16000;
-  } else if (stream->fourcc == GST_MAKE_FOURCC ('m', 'p', '4', 'a')) {
+  } else if (stream->fourcc == FOURCC_mp4a) {
     stream->sampled = TRUE;
   }
 
-  /* sample to chunk */
-  stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc);
-  if (stsc == NULL)
-    goto corrupt_file;
-  stsc_data = (const guint8 *) stsc->data;
-  /* sample size */
-  stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz);
-  if (stsz == NULL)
-    goto corrupt_file;
-  stsz_data = (const guint8 *) stsz->data;
-  /* chunk offsets */
-  stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
-  co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
-  if (stco == NULL && co64 == NULL)
-    goto corrupt_file;
-  if (stco)
-    stco_data = (const guint8 *) stco->data;
-  else
-    stco_data = NULL;
-  /* sample time */
-  stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts);
-  if (stts == NULL)
-    goto corrupt_file;
-  /* sample sync, can be NULL */
-  stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
-
-  sample_size = QTDEMUX_GUINT32_GET (stsz_data + 12);
-  if (sample_size == 0 || stream->sampled) {
-    n_samples = QTDEMUX_GUINT32_GET (stsz_data + 16);
-    GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
-        n_samples);
-    stream->n_samples = n_samples;
-    samples = g_new0 (QtDemuxSample, n_samples);
-    stream->samples = samples;
-
-    for (i = 0; i < n_samples; i++) {
-      if (sample_size == 0)
-        samples[i].size = QTDEMUX_GUINT32_GET (stsz_data + i * 4 + 20);
-      else
-        samples[i].size = sample_size;
-
-      GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
-      /* init other fields to defaults for this sample */
-      samples[i].keyframe = FALSE;
-    }
-    n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc_data + 12);
-    index = 0;
-    offset = 16;
-    for (i = 0; i < n_samples_per_chunk; i++) {
-      guint32 first_chunk, last_chunk;
-      guint32 samples_per_chunk;
-
-      first_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 0) - 1;
-      if (i == n_samples_per_chunk - 1) {
-        last_chunk = G_MAXUINT32;
-      } else {
-        last_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 12) - 1;
-      }
-      samples_per_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 4);
-
-      for (j = first_chunk; j < last_chunk; j++) {
-        guint64 chunk_offset;
-
-        if (stco) {
-          chunk_offset = QTDEMUX_GUINT32_GET (stco_data + 16 + j * 4);
-        } else {
-          chunk_offset =
-              QTDEMUX_GUINT64_GET ((guint8 *) co64->data + 16 + j * 8);
-        }
-        for (k = 0; k < samples_per_chunk; k++) {
-          GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
-              index, chunk_offset);
-          samples[index].chunk = j;
-          samples[index].offset = chunk_offset;
-          chunk_offset += samples[index].size;
-          index++;
-          if (index >= n_samples)
-            goto done;
-        }
-      }
-    }
-  done:
-
-    n_sample_times = QTDEMUX_GUINT32_GET ((guint8 *) stts->data + 12);
-    timestamp = 0;
-    stream->min_duration = 0;
-    time = 0;
-    index = 0;
-    for (i = 0; i < n_sample_times; i++) {
-      guint32 n;
-      guint32 duration;
-
-      n = QTDEMUX_GUINT32_GET ((guint8 *) stts->data + 16 + 8 * i);
-      duration = QTDEMUX_GUINT32_GET ((guint8 *) stts->data + 16 + 8 * i + 4);
-      for (j = 0; j < n; j++) {
-        GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT,
-            index, GST_TIME_ARGS (timestamp));
-
-        samples[index].timestamp = timestamp;
-        /* take first duration for fps */
-        if (stream->min_duration == 0)
-          stream->min_duration = duration;
-        /* add non-scaled values to avoid rounding errors */
-        time += duration;
-        timestamp = gst_util_uint64_scale_int (time,
-            GST_SECOND, stream->timescale);
-        samples[index].duration = timestamp - samples[index].timestamp;
-
-        index++;
-      }
-    }
-    if (stss) {
-      /* mark keyframes */
-      guint32 n_sample_syncs;
-
-      n_sample_syncs = QTDEMUX_GUINT32_GET ((guint8 *) stss->data + 12);
-      if (n_sample_syncs == 0) {
-        stream->all_keyframe = TRUE;
-      } else {
-        offset = 16;
-        for (i = 0; i < n_sample_syncs; i++) {
-          /* not that the first sample is index 1, not 0 */
-          index = QTDEMUX_GUINT32_GET ((guint8 *) stss->data + offset);
-          samples[index - 1].keyframe = TRUE;
-          offset += 4;
-        }
-      }
-    } else {
-      /* no stss, all samples are keyframes */
-      stream->all_keyframe = TRUE;
-    }
-  } else {
-    GST_DEBUG_OBJECT (qtdemux,
-        "stsz sample_size %d != 0, treating chunks as samples", sample_size);
-
-    /* treat chunks as samples */
-    if (stco) {
-      n_samples = QTDEMUX_GUINT32_GET (stco_data + 12);
-    } else {
-      n_samples = QTDEMUX_GUINT32_GET ((guint8 *) co64->data + 12);
-    }
-    stream->n_samples = n_samples;
-    GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
-    samples = g_new0 (QtDemuxSample, n_samples);
-    stream->samples = samples;
-
-    n_samples_per_chunk = QTDEMUX_GUINT32_GET (stsc_data + 12);
-    GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
-    offset = 16;
-    sample_index = 0;
-    timestamp = 0;
-    for (i = 0; i < n_samples_per_chunk; i++) {
-      guint32 first_chunk, last_chunk;
-      guint32 samples_per_chunk;
-
-      first_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 0) - 1;
-      /* the last chunk of each entry is calculated by taking the first chunk
-       * of the next entry; except if there is no next, where we fake it with
-       * INT_MAX */
-      if (i == n_samples_per_chunk - 1) {
-        last_chunk = G_MAXUINT32;
-      } else {
-        last_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 12) - 1;
-      }
-      samples_per_chunk = QTDEMUX_GUINT32_GET (stsc_data + 16 + i * 12 + 4);
-
-      GST_LOG_OBJECT (qtdemux,
-          "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
-          first_chunk, last_chunk, samples_per_chunk);
-
-      for (j = first_chunk; j < last_chunk; j++) {
-        guint64 chunk_offset;
-
-        if (j >= n_samples)
-          goto done2;
-        if (stco) {
-          chunk_offset = QTDEMUX_GUINT32_GET (stco_data + 16 + j * 4);
-        } else {
-          chunk_offset =
-              QTDEMUX_GUINT64_GET ((guint8 *) co64->data + 16 + j * 8);
-        }
-        GST_LOG_OBJECT (qtdemux,
-            "Creating entry %d with offset %" G_GUINT64_FORMAT, j,
-            chunk_offset);
-
-        samples[j].chunk = j;
-        samples[j].offset = chunk_offset;
-
-        if (stream->samples_per_frame * stream->bytes_per_frame) {
-          samples[j].size = (samples_per_chunk * stream->n_channels) /
-              stream->samples_per_frame * stream->bytes_per_frame;
-        } else {
-          samples[j].size = samples_per_chunk;
-        }
-
-        GST_INFO_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
-            ", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size);
-
-        samples[j].timestamp = timestamp;
-        sample_index += samples_per_chunk;
-
-        timestamp = gst_util_uint64_scale_int (sample_index,
-            GST_SECOND, stream->timescale);
-        samples[j].duration = timestamp - samples[j].timestamp;
-
-        samples[j].keyframe = TRUE;
-      }
-    }
-  }
-done2:
-
-  /* parse and prepare segment info from the edit list */
-  GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
-  stream->n_segments = 0;
-  stream->segments = NULL;
-  if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
-    GNode *elst;
-    gint n_segments;
-    gint i, count;
-    guint64 time, stime;
-    guint8 *buffer;
-
-    GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
-    if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
-      goto done3;
-
-    buffer = elst->data;
-
-    n_segments = QTDEMUX_GUINT32_GET (buffer + 12);
-
-    /* we might allocate a bit too much, at least allocate 1 segment */
-    stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
-
-    /* segments always start from 0 */
-    time = 0;
-    stime = 0;
-    count = 0;
-    for (i = 0; i < n_segments; i++) {
-      guint64 duration;
-      guint64 media_time;
-      QtDemuxSegment *segment;
-
-      media_time = QTDEMUX_GUINT32_GET (buffer + 20 + i * 12);
-
-      /* -1 media time is an empty segment, just ignore it */
-      if (media_time == G_MAXUINT32)
-        continue;
-
-      duration = QTDEMUX_GUINT32_GET (buffer + 16 + i * 12);
-
-      segment = &stream->segments[count++];
-
-      /* time and duration expressed in global timescale */
-      segment->time = stime;
-      /* add non scaled values so we don't cause roundoff errors */
-      time += duration;
-      stime = gst_util_uint64_scale_int (time, GST_SECOND, qtdemux->timescale);
-      segment->stop_time = stime;
-      segment->duration = stime - segment->time;
-      /* media_time expressed in stream timescale */
-      segment->media_start =
-          gst_util_uint64_scale_int (media_time, GST_SECOND, stream->timescale);
-      segment->media_stop = segment->media_start + segment->duration;
-      segment->rate = QTDEMUX_FP32_GET (buffer + 24 + i * 12);
-
-      GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
-          ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
-          ", rate %g", i, GST_TIME_ARGS (segment->time),
-          GST_TIME_ARGS (segment->duration),
-          GST_TIME_ARGS (segment->media_start), segment->rate);
-    }
-    GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
-    stream->n_segments = count;
-  }
-done3:
-
-  /* no segments, create one to play the complete trak */
-  if (stream->n_segments == 0) {
-    if (stream->segments == NULL)
-      stream->segments = g_new (QtDemuxSegment, 1);
+  /* collect sample information */
+  if (!qtdemux_parse_samples (qtdemux, stream, stbl))
+    goto samples_failed;
 
-    stream->segments[0].time = 0;
-    stream->segments[0].stop_time = qtdemux->segment.duration;
-    stream->segments[0].duration = qtdemux->segment.duration;
-    stream->segments[0].media_start = 0;
-    stream->segments[0].media_stop = qtdemux->segment.duration;
-    stream->segments[0].rate = 1.0;
-
-    GST_DEBUG_OBJECT (qtdemux, "created dummy segment");
-    stream->n_segments = 1;
-  }
-  GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
+  /* configure segments */
+  if (!qtdemux_parse_segments (qtdemux, stream, trak))
+    goto segments_failed;
 
+  /* now we are ready to add the stream */
   gst_qtdemux_add_stream (qtdemux, stream, list);
-  return;
+
+  return TRUE;
 
 /* ERRORS */
 corrupt_file:
   {
     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
         (_("This file is corrupt and cannot be played.")), (NULL));
-    return;
+    g_free (stream);
+    return FALSE;
   }
 error_encrypted:
   {
     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
         (_("This file is encrypted and cannot be played.")), (NULL));
-    return;
-  }
-}
-
-static void
-qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
-{
-  GNode *meta;
-  GNode *ilst;
-  GNode *node;
-
-  meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
-  if (meta == NULL) {
-    GST_LOG ("no meta");
-    return;
-  }
-
-  ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
-  if (ilst == NULL) {
-    GST_LOG ("no ilst");
-    return;
-  }
-
-  GST_DEBUG_OBJECT (qtdemux, "new tag list");
-  qtdemux->tag_list = gst_tag_list_new ();
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
-  if (node) {
-    qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
-  if (node) {
-    qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
-  } else {
-    node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
-    if (node) {
-      qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
-    } else {
-      node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
-      if (node) {
-        qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
-      }
-    }
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
-  if (node) {
-    qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__day);
-  if (node) {
-    qtdemux_tag_add_date (qtdemux, GST_TAG_DATE, node);
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__too);
-  if (node) {
-    qtdemux_tag_add_str (qtdemux, GST_TAG_COMMENT, node);
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
-  if (node) {
-    qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
-        GST_TAG_TRACK_COUNT, node);
-  }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
-  if (node) {
-    qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
-        GST_TAG_ALBUM_VOLUME_COUNT, node);
-  } else {
-    node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
-    if (node) {
-      qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
-          GST_TAG_ALBUM_VOLUME_COUNT, node);
-    }
+    g_free (stream);
+    return FALSE;
   }
-
-  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
-  if (node) {
-    qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
-  } else {
-    node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
-    if (node) {
-      qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
-    }
+samples_failed:
+  {
+    /* we posted an error already */
+    g_free (stream);
+    return FALSE;
+  }
+segments_failed:
+  {
+    /* we posted an error already */
+    g_free (stream);
+    return FALSE;
+  }
+unknown_stream:
+  {
+    GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
+        GST_FOURCC_ARGS (stream->subtype));
+    g_free (stream);
+    return TRUE;
   }
 }
 
@@ -4096,8 +3080,8 @@ qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, GNode * node)
 
   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
   if (data) {
-    len = QTDEMUX_GUINT32_GET (data->data);
-    type = QTDEMUX_GUINT32_GET ((guint8 *) data->data + 8);
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
     if (type == 0x00000001) {
       s = g_strndup ((char *) data->data + 16, len - 16);
       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", s);
@@ -4118,11 +3102,11 @@ qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
 
   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
   if (data) {
-    len = QTDEMUX_GUINT32_GET (data->data);
-    type = QTDEMUX_GUINT32_GET ((guint8 *) data->data + 8);
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
     if (type == 0x00000000 && len >= 22) {
-      n1 = GST_READ_UINT16_BE ((guint8 *) data->data + 18);
-      n2 = GST_READ_UINT16_BE ((guint8 *) data->data + 20);
+      n1 = QT_UINT16 ((guint8 *) data->data + 18);
+      n2 = QT_UINT16 ((guint8 *) data->data + 20);
       GST_DEBUG_OBJECT (qtdemux, "adding tag %d/%d", n1, n2);
       gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
           tag1, n1, tag2, n2, NULL);
@@ -4140,8 +3124,8 @@ qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, GNode * node)
 
   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
   if (data) {
-    len = QTDEMUX_GUINT32_GET (data->data);
-    type = QTDEMUX_GUINT32_GET ((guint8 *) data->data + 8);
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
     if (type == 0x00000001) {
       guint y, m = 1, d = 1;
       gint ret;
@@ -4167,7 +3151,7 @@ qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, GNode * node)
 static void
 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
 {
-  const gchar *genres[] = {
+  static const gchar *genres[] = {
     "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
     "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
     "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
@@ -4205,10 +3189,10 @@ qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
 
   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
   if (data) {
-    len = QTDEMUX_GUINT32_GET (data->data);
-    type = QTDEMUX_GUINT32_GET ((guint8 *) data->data + 8);
+    len = QT_UINT32 (data->data);
+    type = QT_UINT32 ((guint8 *) data->data + 8);
     if (type == 0x00000000 && len >= 18) {
-      n = GST_READ_UINT16_BE ((guint8 *) data->data + 16);
+      n = QT_UINT16 ((guint8 *) data->data + 16);
       if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
         GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
@@ -4218,6 +3202,315 @@ qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, GNode * node)
   }
 }
 
+static void
+qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
+{
+  GNode *meta;
+  GNode *ilst;
+  GNode *node;
+
+  meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
+  if (meta == NULL) {
+    GST_LOG_OBJECT (qtdemux, "no meta");
+    return;
+  }
+
+  ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
+  if (ilst == NULL) {
+    GST_LOG_OBJECT (qtdemux, "no ilst");
+    return;
+  }
+
+  GST_DEBUG_OBJECT (qtdemux, "new tag list");
+  qtdemux->tag_list = gst_tag_list_new ();
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__nam);
+  if (node) {
+    qtdemux_tag_add_str (qtdemux, GST_TAG_TITLE, node);
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__ART);
+  if (node) {
+    qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
+  } else {
+    node = qtdemux_tree_get_child_by_type (ilst, FOURCC__wrt);
+    if (node) {
+      qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
+    } else {
+      node = qtdemux_tree_get_child_by_type (ilst, FOURCC__grp);
+      if (node) {
+        qtdemux_tag_add_str (qtdemux, GST_TAG_ARTIST, node);
+      }
+    }
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__alb);
+  if (node) {
+    qtdemux_tag_add_str (qtdemux, GST_TAG_ALBUM, node);
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__day);
+  if (node) {
+    qtdemux_tag_add_date (qtdemux, GST_TAG_DATE, node);
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC__too);
+  if (node) {
+    qtdemux_tag_add_str (qtdemux, GST_TAG_COMMENT, node);
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_trkn);
+  if (node) {
+    qtdemux_tag_add_num (qtdemux, GST_TAG_TRACK_NUMBER,
+        GST_TAG_TRACK_COUNT, node);
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disc);
+  if (node) {
+    qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
+        GST_TAG_ALBUM_VOLUME_COUNT, node);
+  } else {
+    node = qtdemux_tree_get_child_by_type (ilst, FOURCC_disk);
+    if (node) {
+      qtdemux_tag_add_num (qtdemux, GST_TAG_ALBUM_VOLUME_NUMBER,
+          GST_TAG_ALBUM_VOLUME_COUNT, node);
+    }
+  }
+
+  node = qtdemux_tree_get_child_by_type (ilst, FOURCC_gnre);
+  if (node) {
+    qtdemux_tag_add_gnre (qtdemux, GST_TAG_GENRE, node);
+  } else {
+    node = qtdemux_tree_get_child_by_type (ilst, FOURCC__gen);
+    if (node) {
+      qtdemux_tag_add_str (qtdemux, GST_TAG_GENRE, node);
+    }
+  }
+}
+
+typedef struct
+{
+  GstStructure *structure;      /* helper for sort function */
+  gchar *location;
+  guint min_req_bitrate;
+  guint min_req_qt_version;
+} GstQtReference;
+
+static gint
+qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
+{
+  GstQtReference *ref_a = (GstQtReference *) a;
+  GstQtReference *ref_b = (GstQtReference *) b;
+
+  if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
+    return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
+
+  /* known bitrates go before unknown; higher bitrates go first */
+  return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
+}
+
+/* sort the redirects and post a message for the application.
+ */
+static void
+qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
+{
+  GstQtReference *best;
+  GstStructure *s;
+  GstMessage *msg;
+  GValue list_val = { 0, };
+  GList *l;
+
+  g_assert (references != NULL);
+
+  references = g_list_sort (references, qtdemux_redirects_sort_func);
+
+  best = (GstQtReference *) references->data;
+
+  g_value_init (&list_val, GST_TYPE_LIST);
+
+  for (l = references; l != NULL; l = l->next) {
+    GstQtReference *ref = (GstQtReference *) l->data;
+    GValue struct_val = { 0, };
+
+    ref->structure = gst_structure_new ("redirect",
+        "new-location", G_TYPE_STRING, ref->location, NULL);
+
+    if (ref->min_req_bitrate > 0) {
+      gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
+          ref->min_req_bitrate, NULL);
+    }
+
+    g_value_init (&struct_val, GST_TYPE_STRUCTURE);
+    g_value_set_boxed (&struct_val, ref->structure);
+    gst_value_list_append_value (&list_val, &struct_val);
+    g_value_unset (&struct_val);
+    /* don't free anything here yet, since we need best->structure below */
+  }
+
+  g_assert (best != NULL);
+  s = gst_structure_copy (best->structure);
+
+  if (g_list_length (references) > 1) {
+    gst_structure_set_value (s, "locations", &list_val);
+  }
+
+  g_value_unset (&list_val);
+
+  for (l = references; l != NULL; l = l->next) {
+    GstQtReference *ref = (GstQtReference *) l->data;
+
+    gst_structure_free (ref->structure);
+    g_free (ref->location);
+    g_free (ref);
+  }
+  g_list_free (references);
+
+  GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
+  msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
+  gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
+}
+
+/* look for redirect nodes, collect all redirect information and
+ * process it.
+ */
+static gboolean
+qtdemux_parse_redirects (GstQTDemux * qtdemux)
+{
+  GNode *rmra, *rmda, *rdrf;
+
+  rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
+  if (rmra) {
+    GList *redirects = NULL;
+
+    rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
+    while (rmda) {
+      GstQtReference ref = { NULL, NULL, 0, 0 };
+      GNode *rmdr, *rmvc;
+
+      if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
+        ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
+        GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
+            ref.min_req_bitrate);
+      }
+
+      if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
+        guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
+        guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
+
+#ifndef GST_DISABLE_GST_DEBUG
+        guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
+#endif
+        guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
+
+        GST_LOG_OBJECT (qtdemux,
+            "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
+            ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
+            bitmask, check_type);
+        if (package == FOURCC_qtim && check_type == 0) {
+          ref.min_req_qt_version = version;
+        }
+      }
+
+      rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
+      if (rdrf) {
+        guint32 ref_type;
+        guint8 *ref_data;
+
+        ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
+        ref_data = (guint8 *) rdrf->data + 20;
+        if (ref_type == FOURCC_alis) {
+          guint record_len, record_version, fn_len;
+
+          /* MacOSX alias record, google for alias-layout.txt */
+          record_len = QT_UINT16 (ref_data + 4);
+          record_version = QT_UINT16 (ref_data + 4 + 2);
+          fn_len = QT_UINT8 (ref_data + 50);
+          if (record_len > 50 && record_version == 2 && fn_len > 0) {
+            ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
+          }
+        } else if (ref_type == FOURCC_url_) {
+          ref.location = g_strdup ((gchar *) ref_data);
+        } else {
+          GST_DEBUG_OBJECT (qtdemux,
+              "unknown rdrf reference type %" GST_FOURCC_FORMAT,
+              GST_FOURCC_ARGS (ref_type));
+        }
+        if (ref.location != NULL) {
+          GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
+          redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
+        } else {
+          GST_WARNING_OBJECT (qtdemux,
+              "Failed to extract redirect location from rdrf atom");
+        }
+      }
+
+      /* look for others */
+      rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
+    }
+
+    if (redirects != NULL) {
+      qtdemux_process_redirects (qtdemux, redirects);
+    }
+  }
+  return TRUE;
+}
+
+/* we have read th complete moov node now.
+ * This function parses all of the relevant info, creates the traks and
+ * prepares all data structures for playback
+ */
+static gboolean
+qtdemux_parse_tree (GstQTDemux * qtdemux)
+{
+  GNode *mvhd;
+  GNode *trak;
+  GNode *udta;
+  gint64 duration;
+
+  mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
+  if (mvhd == NULL) {
+    GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
+    return qtdemux_parse_redirects (qtdemux);
+  }
+
+  qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
+  qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
+
+  GST_INFO_OBJECT (qtdemux, "timescale: %d", qtdemux->timescale);
+  GST_INFO_OBJECT (qtdemux, "duration: %d", qtdemux->duration);
+
+  /* set duration in the segment info */
+  gst_qtdemux_get_duration (qtdemux, &duration);
+  gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
+
+  /* parse all traks */
+  trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
+  while (trak) {
+    qtdemux_parse_trak (qtdemux, trak);
+    /* iterate all siblings */
+    trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
+  }
+  gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
+
+  /* find and push tags, we do this after adding the pads so we can push the
+   * tags downstream as well. */
+  udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
+  if (udta) {
+    qtdemux_parse_udta (qtdemux, udta);
+
+    if (qtdemux->tag_list) {
+      GST_DEBUG_OBJECT (qtdemux,
+          "calling gst_element_found_tags with %" GST_PTR_FORMAT,
+          qtdemux->tag_list);
+      gst_element_found_tags (GST_ELEMENT_CAST (qtdemux), qtdemux->tag_list);
+      qtdemux->tag_list = NULL;
+    }
+  } else {
+    GST_LOG_OBJECT (qtdemux, "No udta node found.");
+  }
+  return TRUE;
+}
+
 /* taken from ffmpeg */
 static unsigned int
 get_size (guint8 * ptr, guint8 ** end)
@@ -4243,7 +3536,7 @@ static void
 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
     GNode * esds, GstTagList * list)
 {
-  int len = QTDEMUX_GUINT32_GET (esds->data);
+  int len = QT_UINT32 (esds->data);
   guint8 *ptr = esds->data;
   guint8 *end = ptr + len;
   int tag;
@@ -4253,10 +3546,10 @@ gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
 
   qtdemux_dump_mem (ptr, len);
   ptr += 8;
-  GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QTDEMUX_GUINT32_GET (ptr));
+  GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
   ptr += 4;
   while (ptr < end) {
-    tag = QTDEMUX_GUINT8_GET (ptr);
+    tag = QT_UINT8 (ptr);
     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
     ptr++;
     len = get_size (ptr, &ptr);
@@ -4264,22 +3557,17 @@ gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
 
     switch (tag) {
       case 0x03:
-        GST_DEBUG_OBJECT (qtdemux, "ID %04x", QTDEMUX_GUINT16_GET (ptr));
-        GST_DEBUG_OBJECT (qtdemux, "priority %04x",
-            QTDEMUX_GUINT8_GET (ptr + 2));
+        GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
+        GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
         ptr += 3;
         break;
       case 0x04:
-        object_type_id = QTDEMUX_GUINT8_GET (ptr);
+        object_type_id = QT_UINT8 (ptr);
         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
-        GST_DEBUG_OBJECT (qtdemux, "stream_type %02x",
-            QTDEMUX_GUINT8_GET (ptr + 1));
-        GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x",
-            QTDEMUX_GUINT24_GET (ptr + 2));
-        GST_DEBUG_OBJECT (qtdemux, "max bitrate %d",
-            QTDEMUX_GUINT32_GET (ptr + 5));
-        GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d",
-            QTDEMUX_GUINT32_GET (ptr + 9));
+        GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
+        GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
+        GST_DEBUG_OBJECT (qtdemux, "max bitrate %d", QT_UINT32 (ptr + 5));
+        GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d", QT_UINT32 (ptr + 9));
         ptr += 13;
         break;
       case 0x05:
@@ -4290,11 +3578,11 @@ gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
         ptr += len;
         break;
       case 0x06:
-        GST_DEBUG_OBJECT (qtdemux, "data %02x", QTDEMUX_GUINT8_GET (ptr));
+        GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
         ptr += 1;
         break;
       default:
-        GST_ERROR ("parse error");
+        GST_ERROR_OBJECT (qtdemux, "parse error");
     }
   }
 
@@ -4305,6 +3593,8 @@ gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
     memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
     qtdemux_dump_mem (GST_BUFFER_DATA (buffer), data_len);
 
+    GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
+
     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
         buffer, NULL);
     gst_buffer_unref (buffer);
@@ -4378,14 +3668,16 @@ qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
       GstCaps *caps;
 
       _codec ("Raw RGB video");
-      bps = QTDEMUX_GUINT16_GET (stsd_data + 98);
+      bps = QT_UINT16 (stsd_data + 98);
+      /* set common stuff */
       caps = gst_caps_new_simple ("video/x-raw-rgb",
-          "endianness", G_TYPE_INT, G_BYTE_ORDER, "bpp", G_TYPE_INT, bps, NULL);
+          "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
+          NULL);
 
       switch (bps) {
         case 15:
           gst_caps_set_simple (caps,
-              "depth", G_TYPE_INT, 16,
+              "bpp", G_TYPE_INT, 16,
               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
               "red_mask", G_TYPE_INT, 0x7c00,
               "green_mask", G_TYPE_INT, 0x03e0,
@@ -4393,7 +3685,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
           break;
         case 16:
           gst_caps_set_simple (caps,
-              "depth", G_TYPE_INT, 16,
+              "bpp", G_TYPE_INT, 16,
               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
               "red_mask", G_TYPE_INT, 0xf800,
               "green_mask", G_TYPE_INT, 0x07e0,
@@ -4401,7 +3693,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
           break;
         case 24:
           gst_caps_set_simple (caps,
-              "depth", G_TYPE_INT, 24,
+              "bpp", G_TYPE_INT, 24,
               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
               "red_mask", G_TYPE_INT, 0xff0000,
               "green_mask", G_TYPE_INT, 0x00ff00,
@@ -4409,7 +3701,7 @@ qtdemux_video_caps (GstQTDemux * qtdemux, guint32 fourcc,
           break;
         case 32:
           gst_caps_set_simple (caps,
-              "depth", G_TYPE_INT, 32,
+              "bpp", G_TYPE_INT, 32,
               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
               "alpha_mask", G_TYPE_INT, 0xff000000,
               "red_mask", G_TYPE_INT, 0x00ff0000,
@@ -4624,9 +3916,9 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
       /* FIXME: QDesign music version 2 (no constant) */
       if (data) {
         return gst_caps_new_simple ("audio/x-qdm2",
-            "framesize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 52),
-            "bitrate", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 40),
-            "blocksize", G_TYPE_INT, QTDEMUX_GUINT32_GET (data + 44), NULL);
+            "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
+            "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
+            "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
       } else {
         return gst_caps_new_simple ("audio/x-qdm2", NULL);
       }
@@ -4653,18 +3945,13 @@ qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
       /* QUALCOMM PureVoice */
     default:
-#if 0
-      g_critical ("Don't know how to convert fourcc '%" GST_FOURCC_FORMAT
-          "' to caps", GST_FOURCC_ARGS (fourcc));
-      return NULL;
-#endif
-      {
-        char *s;
+    {
+      char *s;
 
-        s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
-            GST_FOURCC_ARGS (fourcc));
-        return gst_caps_new_simple (s, NULL);
-      }
+      s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (fourcc));
+      return gst_caps_new_simple (s, NULL);
+    }
   }
 }
 
index 0598de0..13316a4 100644 (file)
@@ -37,7 +37,7 @@ G_BEGIN_DECLS
 #define GST_IS_QTDEMUX_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QTDEMUX))
 
-#define GST_QT_DEMUX_CAST(obj) ((GstQTDemux *)(obj))
+#define GST_QTDEMUX_CAST(obj) ((GstQTDemux *)(obj))
 
 #define GST_QTDEMUX_MAX_STREAMS         8
 
@@ -52,9 +52,9 @@ struct _GstQTDemux {
   GstPad *sinkpad;
 
   QtDemuxStream *streams[GST_QTDEMUX_MAX_STREAMS];
-  gint n_streams;
-  gint n_video_streams;
-  gint n_audio_streams;
+  gint     n_streams;
+  gint     n_video_streams;
+  gint     n_audio_streams;
 
   GNode *moov_node;
   GNode *moov_node_compressed;
@@ -80,7 +80,6 @@ struct _GstQTDemux {
   GstTagList *tag_list;
 
   /* track stuff */
-
   guint64 last_ts;
 
   /* configured playback region */
diff --git a/gst/qtdemux/qtdemux_dump.c b/gst/qtdemux/qtdemux_dump.c
new file mode 100644 (file)
index 0000000..561b20d
--- /dev/null
@@ -0,0 +1,375 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+
+#if 0
+#define qtdemux_dump_mem(a,b)  gst_util_dump_mem(a,b)
+#else
+#define qtdemux_dump_mem(a,b)   /* */
+#endif
+
+void
+qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  creation time: %u", depth, "", QT_UINT32 (buffer + 12));
+  GST_LOG ("%*s  modify time:   %u", depth, "", QT_UINT32 (buffer + 16));
+  GST_LOG ("%*s  time scale:    1/%u sec", depth, "", QT_UINT32 (buffer + 20));
+  GST_LOG ("%*s  duration:      %u", depth, "", QT_UINT32 (buffer + 24));
+  GST_LOG ("%*s  pref. rate:    %g", depth, "", QT_FP32 (buffer + 28));
+  GST_LOG ("%*s  pref. volume:  %g", depth, "", QT_FP16 (buffer + 32));
+  GST_LOG ("%*s  preview time:  %u", depth, "", QT_UINT32 (buffer + 80));
+  GST_LOG ("%*s  preview dur.:  %u", depth, "", QT_UINT32 (buffer + 84));
+  GST_LOG ("%*s  poster time:   %u", depth, "", QT_UINT32 (buffer + 88));
+  GST_LOG ("%*s  select time:   %u", depth, "", QT_UINT32 (buffer + 92));
+  GST_LOG ("%*s  select dur.:   %u", depth, "", QT_UINT32 (buffer + 96));
+  GST_LOG ("%*s  current time:  %u", depth, "", QT_UINT32 (buffer + 100));
+  GST_LOG ("%*s  next track ID: %d", depth, "", QT_UINT32 (buffer + 104));
+}
+
+void
+qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  creation time: %u", depth, "", QT_UINT32 (buffer + 12));
+  GST_LOG ("%*s  modify time:   %u", depth, "", QT_UINT32 (buffer + 16));
+  GST_LOG ("%*s  track ID:      %u", depth, "", QT_UINT32 (buffer + 20));
+  GST_LOG ("%*s  duration:      %u", depth, "", QT_UINT32 (buffer + 28));
+  GST_LOG ("%*s  layer:         %u", depth, "", QT_UINT16 (buffer + 36));
+  GST_LOG ("%*s  alt group:     %u", depth, "", QT_UINT16 (buffer + 38));
+  GST_LOG ("%*s  volume:        %g", depth, "", QT_FP16 (buffer + 44));
+  GST_LOG ("%*s  track width:   %g", depth, "", QT_FP32 (buffer + 84));
+  GST_LOG ("%*s  track height:  %g", depth, "", QT_FP32 (buffer + 88));
+
+}
+
+void
+qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %u", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    track dur:     %u", depth, "",
+        QT_UINT32 (buffer + 16 + i * 12));
+    GST_LOG ("%*s    media time:    %u", depth, "",
+        QT_UINT32 (buffer + 20 + i * 12));
+    GST_LOG ("%*s    media rate:    %g", depth, "",
+        QT_FP32 (buffer + 24 + i * 12));
+  }
+}
+
+void
+qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  creation time: %u", depth, "", QT_UINT32 (buffer + 12));
+  GST_LOG ("%*s  modify time:   %u", depth, "", QT_UINT32 (buffer + 16));
+  GST_LOG ("%*s  time scale:    1/%u sec", depth, "", QT_UINT32 (buffer + 20));
+  GST_LOG ("%*s  duration:      %u", depth, "", QT_UINT32 (buffer + 24));
+  GST_LOG ("%*s  language:      %u", depth, "", QT_UINT16 (buffer + 28));
+  GST_LOG ("%*s  quality:       %u", depth, "", QT_UINT16 (buffer + 30));
+
+}
+
+void
+qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  type:          %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (QT_FOURCC (buffer + 12)));
+  GST_LOG ("%*s  subtype:       %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (QT_FOURCC (buffer + 16)));
+  GST_LOG ("%*s  manufacturer:  %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (QT_FOURCC (buffer + 20)));
+  GST_LOG ("%*s  flags:         %08x", depth, "", QT_UINT32 (buffer + 24));
+  GST_LOG ("%*s  flags mask:    %08x", depth, "", QT_UINT32 (buffer + 28));
+  GST_LOG ("%*s  name:          %*s", depth, "",
+      QT_UINT8 (buffer + 32), (char *) (buffer + 33));
+
+}
+
+void
+qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  mode/color:    %08x", depth, "", QT_UINT32 (buffer + 16));
+}
+
+void
+qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int n;
+  int i;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %u", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    size:          %u", depth, "",
+        QT_UINT32 (buffer + offset));
+    GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
+        GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 4)));
+    offset += QT_UINT32 (buffer + offset);
+  }
+}
+
+void
+qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    size:          %u", depth, "",
+        QT_UINT32 (buffer + offset));
+    GST_LOG ("%*s    type:          %" GST_FOURCC_FORMAT, depth, "",
+        GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 4)));
+    GST_LOG ("%*s    data reference:%d", depth, "",
+        QT_UINT16 (buffer + offset + 14));
+
+    GST_LOG ("%*s    version/rev.:  %08x", depth, "",
+        QT_UINT32 (buffer + offset + 16));
+    GST_LOG ("%*s    vendor:        %" GST_FOURCC_FORMAT, depth, "",
+        GST_FOURCC_ARGS (QT_FOURCC (buffer + offset + 20)));
+    GST_LOG ("%*s    temporal qual: %u", depth, "",
+        QT_UINT32 (buffer + offset + 24));
+    GST_LOG ("%*s    spatial qual:  %u", depth, "",
+        QT_UINT32 (buffer + offset + 28));
+    GST_LOG ("%*s    width:         %u", depth, "",
+        QT_UINT16 (buffer + offset + 32));
+    GST_LOG ("%*s    height:        %u", depth, "",
+        QT_UINT16 (buffer + offset + 34));
+    GST_LOG ("%*s    horiz. resol:  %g", depth, "",
+        QT_FP32 (buffer + offset + 36));
+    GST_LOG ("%*s    vert. resol.:  %g", depth, "",
+        QT_FP32 (buffer + offset + 40));
+    GST_LOG ("%*s    data size:     %u", depth, "",
+        QT_UINT32 (buffer + offset + 44));
+    GST_LOG ("%*s    frame count:   %u", depth, "",
+        QT_UINT16 (buffer + offset + 48));
+    GST_LOG ("%*s    compressor:    %d %d %d", depth, "",
+        QT_UINT8 (buffer + offset + 49),
+        QT_UINT8 (buffer + offset + 50), QT_UINT8 (buffer + offset + 51));
+    //(char *) (buffer + offset + 51));
+    GST_LOG ("%*s    depth:         %u", depth, "",
+        QT_UINT16 (buffer + offset + 82));
+    GST_LOG ("%*s    color table ID:%u", depth, "",
+        QT_UINT16 (buffer + offset + 84));
+
+    offset += QT_UINT32 (buffer + offset);
+  }
+}
+
+void
+qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    count:         %u", depth, "",
+        QT_UINT32 (buffer + offset));
+    GST_LOG ("%*s    duration:      %u", depth, "",
+        QT_UINT32 (buffer + offset + 4));
+
+    offset += 8;
+  }
+}
+
+void
+qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    sample:        %u", depth, "",
+        QT_UINT32 (buffer + offset));
+
+    offset += 4;
+  }
+}
+
+void
+qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    first chunk:   %u", depth, "",
+        QT_UINT32 (buffer + offset));
+    GST_LOG ("%*s    sample per ch: %u", depth, "",
+        QT_UINT32 (buffer + offset + 4));
+    GST_LOG ("%*s    sample desc id:%08x", depth, "",
+        QT_UINT32 (buffer + offset + 8));
+
+    offset += 12;
+  }
+}
+
+void
+qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  //int i;
+  int n;
+  int offset;
+  int sample_size;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  sample_size = QT_UINT32 (buffer + 12);
+  GST_LOG ("%*s  sample size:   %d", depth, "", sample_size);
+  if (sample_size == 0) {
+    GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 16));
+    n = QT_UINT32 (buffer + 16);
+    offset = 20;
+#if 0
+    for (i = 0; i < n; i++) {
+      GST_LOG ("%*s    sample size:   %u", depth, "",
+          QT_UINT32 (buffer + offset));
+
+      offset += 4;
+    }
+#endif
+  }
+}
+
+void
+qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  n = QT_UINT32 (buffer + 12);
+  GST_LOG ("%*s  n entries:     %d", depth, "", n);
+  offset = 16;
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    chunk offset:  %d", depth, "",
+        QT_UINT32 (buffer + offset));
+
+    offset += 4;
+  }
+}
+
+void
+qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  //int i;
+  int n;
+  int offset;
+
+  GST_LOG ("%*s  version/flags: %08x", depth, "", QT_UINT32 (buffer + 8));
+  GST_LOG ("%*s  n entries:     %d", depth, "", QT_UINT32 (buffer + 12));
+  n = QT_UINT32 (buffer + 12);
+  offset = 16;
+#if 0
+  for (i = 0; i < n; i++) {
+    GST_LOG ("%*s    chunk offset:  %" G_GUINT64_FORMAT, depth, "",
+        QTDEMUX_GUINT64_GET (buffer + offset));
+
+    offset += 8;
+  }
+#endif
+}
+
+void
+qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  compression type: %" GST_FOURCC_FORMAT, depth, "",
+      GST_FOURCC_ARGS (QT_FOURCC (buffer + 8)));
+}
+
+void
+qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  GST_LOG ("%*s  length: %d", depth, "", QT_UINT32 (buffer + 8));
+}
+
+void
+qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer, int depth)
+{
+  int len;
+
+  GST_LOG ("%*s  length: %d", depth, "", QT_UINT32 (buffer + 0));
+
+  len = QT_UINT32 (buffer + 0);
+  qtdemux_dump_mem (buffer, len);
+
+}
+
+static gboolean
+qtdemux_node_dump_foreach (GNode * node, gpointer qtdemux)
+{
+  guint8 *buffer = (guint8 *) node->data;
+  guint32 node_length;
+  guint32 fourcc;
+  const QtNodeType *type;
+  int depth;
+
+  node_length = GST_READ_UINT32_BE (buffer);
+  fourcc = GST_READ_UINT32_LE (buffer + 4);
+
+  type = qtdemux_type_get (fourcc);
+
+  depth = (g_node_depth (node) - 1) * 2;
+  GST_LOG ("%*s'%" GST_FOURCC_FORMAT "', [%d], %s",
+      depth, "", GST_FOURCC_ARGS (fourcc), node_length, type->name);
+
+  if (type->dump)
+    type->dump (GST_QTDEMUX_CAST (qtdemux), buffer, depth);
+
+  return FALSE;
+}
+
+void
+qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node)
+{
+  g_node_traverse (qtdemux->moov_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
+      qtdemux_node_dump_foreach, qtdemux);
+}
diff --git a/gst/qtdemux/qtdemux_dump.h b/gst/qtdemux/qtdemux_dump.h
new file mode 100644 (file)
index 0000000..ce26acc
--- /dev/null
@@ -0,0 +1,50 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_QTDEMUX_DUMP_H__
+#define __GST_QTDEMUX_DUMP_H__
+
+#include <gst/gst.h>
+#include <qtdemux.h>
+
+G_BEGIN_DECLS
+
+void qtdemux_dump_mvhd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_tkhd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_elst (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_mdhd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_hdlr (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_vmhd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_dref (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stsd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stts (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stss (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stsc (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stsz (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_stco (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_co64 (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_dcom (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_cmvd (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+void qtdemux_dump_unknown (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+
+void qtdemux_node_dump (GstQTDemux * qtdemux, GNode * node);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_DUMP_H__ */
diff --git a/gst/qtdemux/qtdemux_fourcc.h b/gst/qtdemux/qtdemux_fourcc.h
new file mode 100644 (file)
index 0000000..8dbb3eb
--- /dev/null
@@ -0,0 +1,132 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_QTDEMUX_FOURCC_H__
+#define __GST_QTDEMUX_FOURCC_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define FOURCC_moov     GST_MAKE_FOURCC('m','o','o','v')
+#define FOURCC_mvhd     GST_MAKE_FOURCC('m','v','h','d')
+#define FOURCC_clip     GST_MAKE_FOURCC('c','l','i','p')
+#define FOURCC_trak     GST_MAKE_FOURCC('t','r','a','k')
+#define FOURCC_udta     GST_MAKE_FOURCC('u','d','t','a')
+#define FOURCC_ctab     GST_MAKE_FOURCC('c','t','a','b')
+#define FOURCC_tkhd     GST_MAKE_FOURCC('t','k','h','d')
+#define FOURCC_crgn     GST_MAKE_FOURCC('c','r','g','n')
+#define FOURCC_matt     GST_MAKE_FOURCC('m','a','t','t')
+#define FOURCC_kmat     GST_MAKE_FOURCC('k','m','a','t')
+#define FOURCC_edts     GST_MAKE_FOURCC('e','d','t','s')
+#define FOURCC_elst     GST_MAKE_FOURCC('e','l','s','t')
+#define FOURCC_load     GST_MAKE_FOURCC('l','o','a','d')
+#define FOURCC_tref     GST_MAKE_FOURCC('t','r','e','f')
+#define FOURCC_imap     GST_MAKE_FOURCC('i','m','a','p')
+#define FOURCC___in     GST_MAKE_FOURCC(' ',' ','i','n')
+#define FOURCC___ty     GST_MAKE_FOURCC(' ',' ','t','y')
+#define FOURCC_mdia     GST_MAKE_FOURCC('m','d','i','a')
+#define FOURCC_mdhd     GST_MAKE_FOURCC('m','d','h','d')
+#define FOURCC_hdlr     GST_MAKE_FOURCC('h','d','l','r')
+#define FOURCC_minf     GST_MAKE_FOURCC('m','i','n','f')
+#define FOURCC_vmhd     GST_MAKE_FOURCC('v','m','h','d')
+#define FOURCC_smhd     GST_MAKE_FOURCC('s','m','h','d')
+#define FOURCC_gmhd     GST_MAKE_FOURCC('g','m','h','d')
+#define FOURCC_gmin     GST_MAKE_FOURCC('g','m','i','n')
+#define FOURCC_dinf     GST_MAKE_FOURCC('d','i','n','f')
+#define FOURCC_dref     GST_MAKE_FOURCC('d','r','e','f')
+#define FOURCC_stbl     GST_MAKE_FOURCC('s','t','b','l')
+#define FOURCC_stsd     GST_MAKE_FOURCC('s','t','s','d')
+#define FOURCC_stts     GST_MAKE_FOURCC('s','t','t','s')
+#define FOURCC_stss     GST_MAKE_FOURCC('s','t','s','s')
+#define FOURCC_stsc     GST_MAKE_FOURCC('s','t','s','c')
+#define FOURCC_stsz     GST_MAKE_FOURCC('s','t','s','z')
+#define FOURCC_stco     GST_MAKE_FOURCC('s','t','c','o')
+#define FOURCC_vide     GST_MAKE_FOURCC('v','i','d','e')
+#define FOURCC_soun     GST_MAKE_FOURCC('s','o','u','n')
+#define FOURCC_strm     GST_MAKE_FOURCC('s','t','r','m')
+#define FOURCC_rtsp     GST_MAKE_FOURCC('r','t','s','p')
+#define FOURCC_co64     GST_MAKE_FOURCC('c','o','6','4')
+#define FOURCC_cmov     GST_MAKE_FOURCC('c','m','o','v')
+#define FOURCC_dcom     GST_MAKE_FOURCC('d','c','o','m')
+#define FOURCC_cmvd     GST_MAKE_FOURCC('c','m','v','d')
+#define FOURCC_hint     GST_MAKE_FOURCC('h','i','n','t')
+#define FOURCC_mp4a     GST_MAKE_FOURCC('m','p','4','a')
+#define FOURCC_mp4v     GST_MAKE_FOURCC('m','p','4','v')
+#define FOURCC_wave     GST_MAKE_FOURCC('w','a','v','e')
+#define FOURCC_appl     GST_MAKE_FOURCC('a','p','p','l')
+#define FOURCC_esds     GST_MAKE_FOURCC('e','s','d','s')
+#define FOURCC_hnti     GST_MAKE_FOURCC('h','n','t','i')
+#define FOURCC_rtp_     GST_MAKE_FOURCC('r','t','p',' ')
+#define FOURCC_sdp_     GST_MAKE_FOURCC('s','d','p',' ')
+#define FOURCC_meta     GST_MAKE_FOURCC('m','e','t','a')
+#define FOURCC_ilst     GST_MAKE_FOURCC('i','l','s','t')
+#define FOURCC__nam     GST_MAKE_FOURCC(0xa9,'n','a','m')
+#define FOURCC__ART     GST_MAKE_FOURCC(0xa9,'A','R','T')
+#define FOURCC__wrt     GST_MAKE_FOURCC(0xa9,'w','r','t')
+#define FOURCC__grp     GST_MAKE_FOURCC(0xa9,'g','r','p')
+#define FOURCC__alb     GST_MAKE_FOURCC(0xa9,'a','l','b')
+#define FOURCC__day     GST_MAKE_FOURCC(0xa9,'d','a','y')
+#define FOURCC_gnre     GST_MAKE_FOURCC('g','n','r','e')
+#define FOURCC_disc     GST_MAKE_FOURCC('d','i','s','c')
+#define FOURCC_disk     GST_MAKE_FOURCC('d','i','s','k')
+#define FOURCC_trkn     GST_MAKE_FOURCC('t','r','k','n')
+#define FOURCC_cpil     GST_MAKE_FOURCC('c','p','i','l')
+#define FOURCC_tmpo     GST_MAKE_FOURCC('t','m','p','o')
+#define FOURCC__too     GST_MAKE_FOURCC(0xa9,'t','o','o')
+#define FOURCC_____     GST_MAKE_FOURCC('-','-','-','-')
+#define FOURCC_free     GST_MAKE_FOURCC('f','r','e','e')
+#define FOURCC_data     GST_MAKE_FOURCC('d','a','t','a')
+#define FOURCC_SVQ3     GST_MAKE_FOURCC('S','V','Q','3')
+#define FOURCC_rmra     GST_MAKE_FOURCC('r','m','r','a')
+#define FOURCC_rmda     GST_MAKE_FOURCC('r','m','d','a')
+#define FOURCC_rdrf     GST_MAKE_FOURCC('r','d','r','f')
+#define FOURCC__gen     GST_MAKE_FOURCC(0xa9, 'g', 'e', 'n')
+#define FOURCC_rmdr     GST_MAKE_FOURCC('r','m','d','r')
+#define FOURCC_rmvc     GST_MAKE_FOURCC('r','m','v','c')
+#define FOURCC_qtim     GST_MAKE_FOURCC('q','t','i','m')
+#define FOURCC_drms     GST_MAKE_FOURCC('d','r','m','s')
+#define FOURCC_avc1     GST_MAKE_FOURCC('a','v','c','1')
+#define FOURCC_avcC     GST_MAKE_FOURCC('a','v','c','C')
+#define FOURCC_VP31     GST_MAKE_FOURCC('V','P','3','1')
+#define FOURCC_rle_     GST_MAKE_FOURCC('r','l','e',' ')
+#define FOURCC_MAC6     GST_MAKE_FOURCC('M','A','C','6')
+#define FOURCC_MAC3     GST_MAKE_FOURCC('M','A','C','3')
+#define FOURCC_ima4     GST_MAKE_FOURCC('i','m','a','4')
+#define FOURCC_ulaw     GST_MAKE_FOURCC('u','l','a','w')
+#define FOURCC_alaw     GST_MAKE_FOURCC('a','l','a','w')
+#define FOURCC_twos     GST_MAKE_FOURCC('t','w','o','s')
+#define FOURCC_sowt     GST_MAKE_FOURCC('s','o','w','t')
+#define FOURCC_raw_     GST_MAKE_FOURCC('r','a','w',' ')
+#define FOURCC_QDM2     GST_MAKE_FOURCC('Q','D','M','2')
+#define FOURCC_alac     GST_MAKE_FOURCC('a','l','a','c')
+#define FOURCC_samr     GST_MAKE_FOURCC('s','a','m','r')
+#define FOURCC_sawb     GST_MAKE_FOURCC('s','a','w','b')
+#define FOURCC_mdat     GST_MAKE_FOURCC('m','d','a','t')
+#define FOURCC_wide     GST_MAKE_FOURCC('w','i','d','e')
+#define FOURCC_PICT     GST_MAKE_FOURCC('P','I','C','T')
+#define FOURCC_pnot     GST_MAKE_FOURCC('p','n','o','t')
+#define FOURCC_zlib     GST_MAKE_FOURCC('z','l','i','b')
+#define FOURCC_alis     GST_MAKE_FOURCC('a','l','i','s')
+#define FOURCC_url_     GST_MAKE_FOURCC('u','r','l',' ')
+#define FOURCC_frma     GST_MAKE_FOURCC('f','r','m','a')
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_FOURCC_H__ */
diff --git a/gst/qtdemux/qtdemux_types.c b/gst/qtdemux/qtdemux_types.c
new file mode 100644 (file)
index 0000000..a8bd541
--- /dev/null
@@ -0,0 +1,128 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "qtdemux_types.h"
+#include "qtdemux_dump.h"
+#include "qtdemux_fourcc.h"
+
+static const QtNodeType qt_node_types[] = {
+  {FOURCC_moov, "movie", QT_FLAG_CONTAINER,},
+  {FOURCC_mvhd, "movie header", 0,
+      qtdemux_dump_mvhd},
+  {FOURCC_clip, "clipping", QT_FLAG_CONTAINER,},
+  {FOURCC_trak, "track", QT_FLAG_CONTAINER,},
+  {FOURCC_udta, "user data", QT_FLAG_CONTAINER,},       /* special container */
+  {FOURCC_ctab, "color table", 0,},
+  {FOURCC_tkhd, "track header", 0,
+      qtdemux_dump_tkhd},
+  {FOURCC_crgn, "clipping region", 0,},
+  {FOURCC_matt, "track matte", QT_FLAG_CONTAINER,},
+  {FOURCC_kmat, "compressed matte", 0,},
+  {FOURCC_edts, "edit", QT_FLAG_CONTAINER,},
+  {FOURCC_elst, "edit list", 0,
+      qtdemux_dump_elst},
+  {FOURCC_load, "track load settings", 0,},
+  {FOURCC_tref, "track reference", QT_FLAG_CONTAINER,},
+  {FOURCC_imap, "track input map", QT_FLAG_CONTAINER,},
+  {FOURCC___in, "track input", 0,},     /* special container */
+  {FOURCC___ty, "input type", 0,},
+  {FOURCC_mdia, "media", QT_FLAG_CONTAINER},
+  {FOURCC_mdhd, "media header", 0,
+      qtdemux_dump_mdhd},
+  {FOURCC_hdlr, "handler reference", 0,
+      qtdemux_dump_hdlr},
+  {FOURCC_minf, "media information", QT_FLAG_CONTAINER},
+  {FOURCC_vmhd, "video media information", 0,
+      qtdemux_dump_vmhd},
+  {FOURCC_smhd, "sound media information", 0},
+  {FOURCC_gmhd, "base media information header", 0},
+  {FOURCC_gmin, "base media info", 0},
+  {FOURCC_dinf, "data information", QT_FLAG_CONTAINER},
+  {FOURCC_dref, "data reference", 0,
+      qtdemux_dump_dref},
+  {FOURCC_stbl, "sample table", QT_FLAG_CONTAINER},
+  {FOURCC_stsd, "sample description", 0,
+      qtdemux_dump_stsd},
+  {FOURCC_stts, "time-to-sample", 0,
+      qtdemux_dump_stts},
+  {FOURCC_stss, "sync sample", 0,
+      qtdemux_dump_stss},
+  {FOURCC_stsc, "sample-to-chunk", 0,
+      qtdemux_dump_stsc},
+  {FOURCC_stsz, "sample size", 0,
+      qtdemux_dump_stsz},
+  {FOURCC_stco, "chunk offset", 0,
+      qtdemux_dump_stco},
+  {FOURCC_co64, "64-bit chunk offset", 0,
+      qtdemux_dump_co64},
+  {FOURCC_vide, "video media", 0},
+  {FOURCC_cmov, "compressed movie", QT_FLAG_CONTAINER},
+  {FOURCC_dcom, "compressed data", 0, qtdemux_dump_dcom},
+  {FOURCC_cmvd, "compressed movie data", 0, qtdemux_dump_cmvd},
+  {FOURCC_hint, "hint", 0,},
+  {FOURCC_mp4a, "mp4a", 0,},
+  {FOURCC_mp4v, "mp4v", 0,},
+  {FOURCC_wave, "wave", QT_FLAG_CONTAINER},
+  {FOURCC_appl, "appl", QT_FLAG_CONTAINER},
+  {FOURCC_esds, "esds", 0},
+  {FOURCC_hnti, "hnti", QT_FLAG_CONTAINER},
+  {FOURCC_rtp_, "rtp ", 0, qtdemux_dump_unknown},
+  {FOURCC_sdp_, "sdp ", 0, qtdemux_dump_unknown},
+  {FOURCC_meta, "meta", 0, qtdemux_dump_unknown},
+  {FOURCC_ilst, "ilst", QT_FLAG_CONTAINER,},
+  {FOURCC__nam, "Name", QT_FLAG_CONTAINER,},
+  {FOURCC__ART, "Artist", QT_FLAG_CONTAINER,},
+  {FOURCC__wrt, "Writer", QT_FLAG_CONTAINER,},
+  {FOURCC__grp, "Group", QT_FLAG_CONTAINER,},
+  {FOURCC__alb, "Album", QT_FLAG_CONTAINER,},
+  {FOURCC__day, "Date", QT_FLAG_CONTAINER,},
+  {FOURCC_gnre, "Genre", QT_FLAG_CONTAINER,},
+  {FOURCC_trkn, "Track Number", QT_FLAG_CONTAINER,},
+  {FOURCC_disc, "Disc Number", QT_FLAG_CONTAINER,},
+  {FOURCC_disk, "Disc Number", QT_FLAG_CONTAINER,},
+  {FOURCC_cpil, "cpil", QT_FLAG_CONTAINER,},
+  {FOURCC_tmpo, "Tempo", QT_FLAG_CONTAINER,},
+  {FOURCC__too, "too", QT_FLAG_CONTAINER,},
+  {FOURCC_____, "----", QT_FLAG_CONTAINER,},
+  {FOURCC_data, "data", 0, qtdemux_dump_unknown},
+  {FOURCC_free, "free", 0,},
+  {FOURCC_SVQ3, "SVQ3", 0,},
+  {FOURCC_rmra, "rmra", QT_FLAG_CONTAINER,},
+  {FOURCC_rmda, "rmda", QT_FLAG_CONTAINER,},
+  {FOURCC_rdrf, "rdrf", 0,},
+  {FOURCC__gen, "Custom Genre", QT_FLAG_CONTAINER,},
+  {0, "unknown", 0,},
+};
+static const int n_qt_node_types =
+    sizeof (qt_node_types) / sizeof (qt_node_types[0]);
+
+const QtNodeType *
+qtdemux_type_get (guint32 fourcc)
+{
+  int i;
+
+  for (i = 0; i < n_qt_node_types; i++) {
+    if (qt_node_types[i].fourcc == fourcc)
+      return qt_node_types + i;
+  }
+
+  GST_WARNING ("unknown QuickTime node type %" GST_FOURCC_FORMAT,
+      GST_FOURCC_ARGS (fourcc));
+  return qt_node_types + n_qt_node_types - 1;
+}
diff --git a/gst/qtdemux/qtdemux_types.h b/gst/qtdemux/qtdemux_types.h
new file mode 100644 (file)
index 0000000..7142410
--- /dev/null
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GST_QTDEMUX_TYPES_H__
+#define __GST_QTDEMUX_TYPES_H__
+
+#include <gst/gst.h>
+
+#include "qtdemux.h"
+
+G_BEGIN_DECLS
+
+typedef void (*QtDumpFunc) (GstQTDemux * qtdemux, guint8 * buffer, int depth);
+
+typedef struct _QtNodeType QtNodeType;
+
+#define QT_UINT32(a)  (GST_READ_UINT32_BE(a))
+#define QT_UINT24(a)  (GST_READ_UINT32_BE(a) >> 8)
+#define QT_UINT16(a)  (GST_READ_UINT16_BE(a))
+#define QT_UINT8(a)   (GST_READ_UINT8(a))
+#define QT_FP32(a)    ((GST_READ_UINT32_BE(a))/65536.0)
+#define QT_FP16(a)    ((GST_READ_UINT16_BE(a))/256.0)
+#define QT_FOURCC(a)  (GST_READ_UINT32_LE(a))
+#define QT_UINT64(a)  ((((guint64)QT_UINT32(a))<<32)|QT_UINT32(((guint8 *)a)+4))
+
+typedef enum {
+  QT_FLAG_NONE      = (0),
+  QT_FLAG_CONTAINER = (1 << 0) 
+} QtFlags;
+
+struct _QtNodeType {
+  guint32      fourcc;
+  const gchar *name;
+  QtFlags      flags;
+  QtDumpFunc   dump;
+};
+
+const QtNodeType *qtdemux_type_get (guint32 fourcc);
+
+G_END_DECLS
+
+#endif /* __GST_QTDEMUX_TYPES_H__ */
diff --git a/gst/qtdemux/qtpalette.h b/gst/qtdemux/qtpalette.h
new file mode 100644 (file)
index 0000000..80ece2a
--- /dev/null
@@ -0,0 +1,137 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_QTPALLETE_H__
+#define __GST_QTPALLETE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+static const guint32 ff_qt_default_palette_2[2] = {
+  0xffffff, 0x000000
+};
+
+static const guint32 ff_qt_default_palette_4[4] = {
+  0x93655e, 0xffffff, 0xdfd0ab, 0x000000
+};
+
+static const guint32 ff_qt_default_palette_16[16] = {
+  0xfffbff, 0xefd9bb, 0xe8c9b1, 0x93655e,
+  0xfcdee8, 0x9d8891, 0xffffff, 0xffffff,
+  0xffffff, 0x474837, 0x7a5e55, 0xdfd0ab,
+  0xfffbf9, 0xe8cac5, 0x8a7c77, 0x000000
+};
+static const guint32 ff_qt_default_palette_256[256] = {
+  0xFFFFFF, 0xFFFFCC, 0xFFFF99, 0xFFFF66, 0xFFFF33, 0xFFFF00,
+  0xFFCCFF, 0xFFCCCC, 0xFFCC99, 0xFFCC66, 0xFFCC33, 0xFFCC00,
+  0xFF99FF, 0xFF99CC, 0xFF9999, 0xFF9966, 0xFF9933, 0xFF9900,
+  0xFF66FF, 0xFF66CC, 0xFF6699, 0xFF6666, 0xFF6633, 0xFF6600,
+  0xFF33FF, 0xFF33CC, 0xFF3399, 0xFF3366, 0xFF3333, 0xFF3300,
+  0xFF00FF, 0xFF00CC, 0xFF0099, 0xFF0066, 0xFF0033, 0xFF0000,
+  0xCCFFFF, 0xCCFFCC, 0xCCFF99, 0xCCFF66, 0xCCFF33, 0xCCFF00,
+  0xCCCCFF, 0xCCCCCC, 0xCCCC99, 0xCCCC66, 0xCCCC33, 0xCCCC00,
+  0xCC99FF, 0xCC99CC, 0xCC9999, 0xCC9966, 0xCC9933, 0xCC9900,
+  0xCC66FF, 0xCC66CC, 0xCC6699, 0xCC6666, 0xCC6633, 0xCC6600,
+  0xCC33FF, 0xCC33CC, 0xCC3399, 0xCC3366, 0xCC3333, 0xCC3300,
+  0xCC00FF, 0xCC00CC, 0xCC0099, 0xCC0066, 0xCC0033, 0xCC0000,
+  0x99FFFF, 0x99FFCC, 0x99FF99, 0x99FF66, 0x99FF33, 0x99FF00,
+  0x99CCFF, 0x99CCCC, 0x99CC99, 0x99CC66, 0x99CC33, 0x99CC00,
+  0x9999FF, 0x9999CC, 0x999999, 0x999966, 0x999933, 0x999900,
+  0x9966FF, 0x9966CC, 0x996699, 0x996666, 0x996633, 0x996600,
+  0x9933FF, 0x9933CC, 0x993399, 0x993366, 0x993333, 0x993300,
+  0x9900FF, 0x9900CC, 0x990099, 0x990066, 0x990033, 0x990000,
+  0x66FFFF, 0x66FFCC, 0x66FF99, 0x66FF66, 0x66FF33, 0x66FF00,
+  0x66CCFF, 0x66CCCC, 0x66CC99, 0x66CC66, 0x66CC33, 0x66CC00,
+  0x6699FF, 0x6699CC, 0x669999, 0x669966, 0x669933, 0x669900,
+  0x6666FF, 0x6666CC, 0x666699, 0x666666, 0x666633, 0x666600,
+  0x6633FF, 0x6633CC, 0x663399, 0x663366, 0x663333, 0x663300,
+  0x6600FF, 0x6600CC, 0x660099, 0x660066, 0x660033, 0x660000,
+  0x33FFFF, 0x33FFCC, 0x33FF99, 0x33FF66, 0x33FF33, 0x33FF00,
+  0x33CCFF, 0x33CCCC, 0x33CC99, 0x33CC66, 0x33CC33, 0x33CC00,
+  0x3399FF, 0x3399CC, 0x339999, 0x339966, 0x339933, 0x339900,
+  0x3366FF, 0x3366CC, 0x336699, 0x336666, 0x336633, 0x336600,
+  0x3333FF, 0x3333CC, 0x333399, 0x333366, 0x333333, 0x333300,
+  0x3300FF, 0x3300CC, 0x330099, 0x330066, 0x330033, 0x330000,
+  0x00FFFF, 0x00FFCC, 0x00FF99, 0x00FF66, 0x00FF33, 0x00FF00,
+  0x00CCFF, 0x00CCCC, 0x00CC99, 0x00CC66, 0x00CC33, 0x00CC00,
+  0x0099FF, 0x0099CC, 0x009999, 0x009966, 0x009933, 0x009900,
+  0x0066FF, 0x0066CC, 0x006699, 0x006666, 0x006633, 0x006600,
+  0x0033FF, 0x0033CC, 0x003399, 0x003366, 0x003333, 0x003300,
+  0x0000FF, 0x0000CC, 0x000099, 0x000066, 0x000033, 0xEE0000,
+  0xDD0000, 0xBB0000, 0xAA0000, 0x880000, 0x770000, 0x550000,
+  0x440000, 0x220000, 0x110000, 0x00EE00, 0x00DD00, 0x00BB00,
+  0x00AA00, 0x008800, 0x007700, 0x005500, 0x004400, 0x002200,
+  0x001100, 0x0000EE, 0x0000DD, 0x0000BB, 0x0000AA, 0x000088,
+  0x000077, 0x000055, 0x000044, 0x000022, 0x000011, 0xEEEEEE,
+  0xDDDDDD, 0xBBBBBB, 0xAAAAAA, 0x888888, 0x777777, 0x555555,
+  0x444444, 0x222222, 0x111111, 0x000000
+};
+
+static const guint32 ff_qt_grayscale_palette_16[16] = {
+  0xffffff, 0xeeeeee, 0xdddddd, 0xcccccc,
+  0xbbbbbb, 0xaaaaaa, 0x999999, 0x888888,
+  0x777777, 0x666666, 0x555555, 0x444444,
+  0x333333, 0x222222, 0x111111, 0x000000
+};
+
+static const guint32 ff_qt_grayscale_palette_256[256] = {
+  0xffffff, 0xfefefe, 0xfdfdfd, 0xfcfcfc, 0xfbfbfb, 0xfafafa, 0xf9f9f9,
+  0xf8f8f8, 0xf7f7f7, 0xf6f6f6, 0xf5f5f5, 0xf4f4f4, 0xf3f3f3, 0xf2f2f2,
+  0xf1f1f1, 0xf0f0f0, 0xefefef, 0xeeeeee, 0xededed, 0xececec, 0xebebeb,
+  0xeaeaea, 0xe9e9e9, 0xe8e8e8, 0xe7e7e7, 0xe6e6e6, 0xe5e5e5, 0xe4e4e4,
+  0xe3e3e3, 0xe2e2e2, 0xe1e1e1, 0xe0e0e0, 0xdfdfdf, 0xdedede, 0xdddddd,
+  0xdcdcdc, 0xdbdbdb, 0xdadada, 0xd9d9d9, 0xd8d8d8, 0xd7d7d7, 0xd6d6d6,
+  0xd5d5d5, 0xd4d4d4, 0xd3d3d3, 0xd2d2d2, 0xd1d1d1, 0xd0d0d0, 0xcfcfcf,
+  0xcecece, 0xcdcdcd, 0xcccccc, 0xcbcbcb, 0xcacaca, 0xc9c9c9, 0xc8c8c8,
+  0xc7c7c7, 0xc6c6c6, 0xc5c5c5, 0xc4c4c4, 0xc3c3c3, 0xc2c2c2, 0xc1c1c1,
+  0xc0c0c0, 0xbfbfbf, 0xbebebe, 0xbdbdbd, 0xbcbcbc, 0xbbbbbb, 0xbababa,
+  0xb9b9b9, 0xb8b8b8, 0xb7b7b7, 0xb6b6b6, 0xb5b5b5, 0xb4b4b4, 0xb3b3b3,
+  0xb2b2b2, 0xb1b1b1, 0xb0b0b0, 0xafafaf, 0xaeaeae, 0xadadad, 0xacacac,
+  0xababab, 0xaaaaaa, 0xa9a9a9, 0xa8a8a8, 0xa7a7a7, 0xa6a6a6, 0xa5a5a5,
+  0xa4a4a4, 0xa3a3a3, 0xa2a2a2, 0xa1a1a1, 0xa0a0a0, 0x9f9f9f, 0x9e9e9e,
+  0x9d9d9d, 0x9c9c9c, 0x9b9b9b, 0x9a9a9a, 0x999999, 0x989898, 0x979797,
+  0x969696, 0x959595, 0x949494, 0x939393, 0x929292, 0x919191, 0x909090,
+  0x8f8f8f, 0x8e8e8e, 0x8d8d8d, 0x8c8c8c, 0x8b8b8b, 0x8a8a8a, 0x898989,
+  0x888888, 0x878787, 0x868686, 0x858585, 0x848484, 0x838383, 0x828282,
+  0x818181, 0x808080, 0x7f7f7f, 0x7e7e7e, 0x7d7d7d, 0x7c7c7c, 0x7b7b7b,
+  0x7a7a7a, 0x797979, 0x787878, 0x777777, 0x767676, 0x757575, 0x747474,
+  0x737373, 0x727272, 0x717171, 0x707070, 0x6f6f6f, 0x6e6e6e, 0x6d6d6d,
+  0x6c6c6c, 0x6b6b6b, 0x6a6a6a, 0x696969, 0x686868, 0x676767, 0x666666,
+  0x656565, 0x646464, 0x636363, 0x626262, 0x616161, 0x606060, 0x5f5f5f,
+  0x5e5e5e, 0x5d5d5d, 0x5c5c5c, 0x5b5b5b, 0x5a5a5a, 0x595959, 0x585858,
+  0x575757, 0x565656, 0x555555, 0x545454, 0x535353, 0x525252, 0x515151,
+  0x505050, 0x4f4f4f, 0x4e4e4e, 0x4d4d4d, 0x4c4c4c, 0x4b4b4b, 0x4a4a4a,
+  0x494949, 0x484848, 0x474747, 0x464646, 0x454545, 0x444444, 0x434343,
+  0x424242, 0x414141, 0x404040, 0x3f3f3f, 0x3e3e3e, 0x3d3d3d, 0x3c3c3c,
+  0x3b3b3b, 0x3a3a3a, 0x393939, 0x383838, 0x373737, 0x363636, 0x353535,
+  0x343434, 0x333333, 0x323232, 0x313131, 0x303030, 0x2f2f2f, 0x2e2e2e,
+  0x2d2d2d, 0x2c2c2c, 0x2b2b2b, 0x2a2a2a, 0x292929, 0x282828, 0x272727,
+  0x262626, 0x252525, 0x242424, 0x232323, 0x222222, 0x212121, 0x202020,
+  0x1f1f1f, 0x1e1e1e, 0x1d1d1d, 0x1c1c1c, 0x1b1b1b, 0x1a1a1a, 0x191919,
+  0x181818, 0x171717, 0x161616, 0x151515, 0x141414, 0x131313, 0x121212,
+  0x111111, 0x101010, 0x0f0f0f, 0x0e0e0e, 0x0d0d0d, 0x0c0c0c, 0x0b0b0b,
+  0x0a0a0a, 0x090909, 0x080808, 0x070707, 0x060606, 0x050505, 0x040404,
+  0x030303, 0x020202, 0x010101, 0x000000
+};
+
+G_END_DECLS
+
+#endif /* __GST_QTPALETTE_H__ */