Handle compressed headers. Fix inappropriate use of bytestream_flush().
authorDavid Schleef <ds@schleef.org>
Mon, 16 Jun 2003 17:39:26 +0000 (17:39 +0000)
committerDavid Schleef <ds@schleef.org>
Mon, 16 Jun 2003 17:39:26 +0000 (17:39 +0000)
Original commit message from CVS:
Handle compressed headers.  Fix inappropriate use of bytestream_flush().
Code cleanup.  Added getcaps and _link functions for src pads.  Extract
and set the size,rate,channels correctly.  Fix some of the caps to
agree with avidemux and/or ffmpeg.

gst/qtdemux/qtdemux.c
gst/qtdemux/qtdemux.h

index 8dc2960c9fbd39647df77d70ec99801ed687e213..2ba7d547520c3cecf67cd16489b596d7cf96a374 100644 (file)
 #include "qtdemux.h"
 
 #include <string.h>
+#include <zlib.h>
+
+#define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a))
+#define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a))
+#define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
+#define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0)
+#define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0)
+#define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a))
+
+#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
 
 typedef struct _QtNode QtNode;
 typedef struct _QtNodeType QtNodeType;
@@ -57,17 +67,26 @@ struct _QtDemuxStream {
   int timescale;
 
   int sample_index;
+
+  int width;
+  int height;
+  double rate;
+  int n_channels;
 };
 
 enum QtDemuxState {
   QTDEMUX_STATE_NULL,
   QTDEMUX_STATE_HEADER,
+  QTDEMUX_STATE_HEADER_SEEKING,
   QTDEMUX_STATE_SEEKING,
   QTDEMUX_STATE_MOVIE,
   QTDEMUX_STATE_SEEKING_EOS,
   QTDEMUX_STATE_EOS,
 };
 
+static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc);
+static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc);
+
 static GstElementDetails 
 gst_qtdemux_details = 
 {
@@ -301,24 +320,32 @@ static void gst_qtdemux_loop_header (GstElement *element)
   int size;
   int ret;
 
-
-  GST_DEBUG(0,"loop at position %d",(int)gst_bytestream_tell(qtdemux->bs));
+  /* FIXME _tell gets the offset wrong */
+  //cur_offset = gst_bytestream_tell(qtdemux->bs);
+  
+  cur_offset = qtdemux->offset;
+  GST_DEBUG(0,"loop at position %d",cur_offset);
 
   switch(qtdemux->state){
   case QTDEMUX_STATE_HEADER:
   {
-    ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
-    if(ret<16){
-      gst_qtdemux_handle_sink_event(qtdemux);
-      return;
-    }
+    do{
+      ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16);
+      if(ret<16){
+        if(!gst_qtdemux_handle_sink_event(qtdemux)){
+          return;
+       }
+      }else{
+       break;
+      }
+    }while(1);
 
     length = GUINT32_FROM_BE(*(guint32 *)data);
     GST_DEBUG(0,"length %08x",length);
     fourcc = GUINT32_FROM_LE(*(guint32 *)(data+4));
     GST_DEBUG(0,"fourcc " GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc));
     if(length==0){
-      length = gst_bytestream_length(qtdemux->bs) - gst_bytestream_tell(qtdemux->bs);
+      length = gst_bytestream_length(qtdemux->bs) - cur_offset;
     }
     if(length==1){
       guint32 length1, length2;
@@ -333,50 +360,42 @@ static void gst_qtdemux_loop_header (GstElement *element)
   
     switch(fourcc){
       case GST_MAKE_FOURCC('m','d','a','t'):
-      {
-        int ret;
-        int pos;
-  
-        pos = gst_bytestream_tell(qtdemux->bs);
-        ret = gst_bytestream_seek(qtdemux->bs, pos + length, GST_SEEK_METHOD_SET);
-        GST_DEBUG(0,"seek returned %d",ret);
-        return;
-      }
+      case GST_MAKE_FOURCC('f','r','e','e'):
+      case GST_MAKE_FOURCC('w','i','d','e'):
+        break;
       case GST_MAKE_FOURCC('m','o','o','v'):
       {
         GstBuffer *moov;
-        guint32 n_read;
   
-        n_read = gst_bytestream_read(qtdemux->bs, &moov, length);
-        if(n_read<length){
-         /* FIXME */
-         g_warning("need to handle event\n");
-        }
+       do{
+          ret = gst_bytestream_read(qtdemux->bs, &moov, length);
+          if(ret < length){
+            GST_DEBUG(0,"read failed (%d < %d)",ret,length);
+            if(!gst_qtdemux_handle_sink_event(qtdemux)){
+             return;
+           }
+          }else{
+           break;
+         }
+       }while(1);
+
         qtdemux_parse_moov(qtdemux, GST_BUFFER_DATA(moov), length);
         if(0)qtdemux_node_dump(qtdemux, qtdemux->moov_node);
         qtdemux_parse_tree(qtdemux);
         qtdemux->state = QTDEMUX_STATE_MOVIE;
         break;
       }
-      case GST_MAKE_FOURCC('f','r','e','e'):
-      {
-        gst_bytestream_flush(qtdemux->bs, length);
-        break;
-      }
-      case GST_MAKE_FOURCC('w','i','d','e'):
-      {
-        gst_bytestream_flush(qtdemux->bs, length);
-        break;
-      }
       default:
       {
-        g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT "\n",
-            GST_MAKE_FOURCC('1','2','3','4'),
-            GST_FOURCC_ARGS(GST_MAKE_FOURCC('1','2','3','4')),gst_bytestream_tell(qtdemux->bs));
-        gst_bytestream_flush(qtdemux->bs, length);
+        g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n",
+           fourcc, GST_FOURCC_ARGS(fourcc), cur_offset);
         break;
       }
     }
+    ret = gst_bytestream_seek(qtdemux->bs, cur_offset + length,
+        GST_SEEK_METHOD_SET);
+    qtdemux->offset = cur_offset + length;
+    GST_DEBUG(0,"seek returned %d\n",ret);
     break;
   }
   case QTDEMUX_STATE_SEEKING_EOS:
@@ -385,7 +404,6 @@ static void gst_qtdemux_loop_header (GstElement *element)
 
     do{
       ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1);
-      g_print("peek_bytes returned %d after EOS seek\n",ret);
       if(ret<1){
         if(!gst_qtdemux_handle_sink_event(qtdemux)){
          return;
@@ -437,23 +455,14 @@ static void gst_qtdemux_loop_header (GstElement *element)
     offset = stream->samples[stream->sample_index].offset;
     size = stream->samples[stream->sample_index].size;
 
+    GST_DEBUG(0,"pushing from stream %d, sample_index=%d offset=%d size=%d",
+       index, stream->sample_index, offset, size);
+
     cur_offset = gst_bytestream_tell(qtdemux->bs);
     if(offset != cur_offset){
       GST_DEBUG(0,"seeking to offset %d",offset);
       ret = gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET);
       GST_DEBUG(0,"seek returned %d",ret);
-#if 0
-      if(!gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET)){
-        GstEvent *event;
-        guint32 remaining;
-
-        g_print("seek failed\n");
-        gst_bytestream_get_status(qtdemux->bs, &remaining, &event);
-
-        gst_pad_push(stream->pad, GST_BUFFER(event));
-        return;
-      }
-#endif
       return;
     }
 
@@ -485,6 +494,60 @@ static void gst_qtdemux_loop_header (GstElement *element)
 
 }
 
+static GstCaps *gst_qtdemux_src_getcaps(GstPad *pad, GstCaps *caps)
+{
+  GstQTDemux *qtdemux;
+  QtDemuxStream *stream;
+  int i;
+
+  GST_DEBUG(0,"gst_qtdemux_src_getcaps");
+
+  qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
+
+  g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), NULL);
+
+  GST_DEBUG(0, "looking for pad %p in qtdemux %p", pad, qtdemux);
+  GST_DEBUG(0, "n_streams is %d", qtdemux->n_streams);
+  for(i=0;i<qtdemux->n_streams;i++){
+    stream = qtdemux->streams[i];
+    if(stream->pad == pad){
+      return stream->caps;
+    }
+  }
+
+  GST_DEBUG(0,"Couldn't find stream cooresponding to pad\n");
+
+  return NULL;
+}
+
+static GstPadLinkReturn
+gst_qtdemux_src_link(GstPad *pad, GstCaps *caps)
+{
+  GstQTDemux *qtdemux;
+  QtDemuxStream *stream;
+  int i;
+
+  GST_DEBUG(0,"gst_qtdemux_src_link");
+
+  qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad));
+
+  GST_DEBUG(0, "looking for pad %p in qtdemux %p", pad, qtdemux);
+  g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), GST_PAD_LINK_REFUSED);
+
+  GST_DEBUG(0, "n_streams is %d", qtdemux->n_streams);
+  for(i=0;i<qtdemux->n_streams;i++){
+    stream = qtdemux->streams[i];
+    GST_DEBUG(0, "pad[%d] is %p", i, stream->pad);
+    if(stream->pad == pad){
+      return GST_PAD_LINK_OK;
+    }
+  }
+
+  GST_DEBUG(0,"Couldn't find stream cooresponding to pad\n");
+
+  return GST_PAD_LINK_REFUSED;
+}
+
 void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
 {
   if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){
@@ -493,12 +556,10 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
          qtdemux->n_video_streams));
     if(stream->caps){
       if(gst_caps_has_property(stream->caps,"width")){
-       /* FIXME */
-        gst_caps_set(stream->caps,"width",GST_PROPS_INT(100));
+        gst_caps_set(stream->caps,"width",GST_PROPS_INT(stream->width));
       }
       if(gst_caps_has_property(stream->caps,"height")){
-       /* FIXME */
-        gst_caps_set(stream->caps,"height",GST_PROPS_INT(100));
+        gst_caps_set(stream->caps,"height",GST_PROPS_INT(stream->height));
       }
     }
     qtdemux->n_video_streams++;
@@ -508,25 +569,31 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
          qtdemux->n_audio_streams));
     if(stream->caps){
       if(gst_caps_has_property(stream->caps,"rate")){
-       /* FIXME */
-        gst_caps_set(stream->caps,"rate",GST_PROPS_INT(44100));
+        gst_caps_set(stream->caps,"rate",GST_PROPS_INT((int)stream->rate));
       }
       if(gst_caps_has_property(stream->caps,"channels")){
-       /* FIXME */
-        gst_caps_set(stream->caps,"channels",GST_PROPS_INT(2));
+        gst_caps_set(stream->caps,"channels",GST_PROPS_INT(stream->n_channels));
       }
     }
-
-    g_print("setting caps to %s\n",gst_caps_to_string(stream->caps));
     qtdemux->n_audio_streams++;
   }
+
+  gst_pad_set_getcaps_function(stream->pad, gst_qtdemux_src_getcaps);
+  gst_pad_set_link_function(stream->pad, gst_qtdemux_src_link);
+
+  qtdemux->streams[qtdemux->n_streams] = stream;
+  qtdemux->n_streams++;
+  GST_DEBUG(0, "n_streams is now %d", qtdemux->n_streams);
+
+  GST_DEBUG(0, "adding pad %p to qtdemux %p", stream->pad, qtdemux);
   gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad);
+
+  /* Note: we need to have everything set up before calling try_set_caps */
   if(stream->caps){
+    g_print("setting caps to %s\n",gst_caps_to_string(stream->caps));
+
     gst_pad_try_set_caps(stream->pad, stream->caps);
   }
-
-  qtdemux->streams[qtdemux->n_streams] = stream;
-  qtdemux->n_streams++;
 }
 
 
@@ -569,6 +636,9 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream)
 #define FOURCC_vide    GST_MAKE_FOURCC('v','i','d','e')
 #define FOURCC_soun    GST_MAKE_FOURCC('s','o','u','n')
 #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')
 
 
 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth);
@@ -585,6 +655,8 @@ static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth);
 static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth);
 static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth);
 static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth);
+static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth);
+static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth);
 
 QtNodeType qt_node_types[] = {
   { FOURCC_moov, "movie",              QT_CONTAINER, },
@@ -637,19 +709,96 @@ QtNodeType qt_node_types[] = {
   { 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 },
   { 0, "unknown", 0 },
 };
 static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]);
 
 
+static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size)
+{
+  return g_malloc(items*size);
+}
+
+static void qtdemux_zfree(void *opaque, void *addr)
+{
+  g_free(addr);
+}
+
+static void *qtdemux_inflate(void *z_buffer, int z_length, int length)
+{
+  void *buffer;
+  z_stream *z;
+  int ret;
+
+  z = g_new0(z_stream, 1);
+  z->zalloc = qtdemux_zalloc;
+  z->zfree = qtdemux_zfree;
+  z->opaque = NULL;
+
+  z->next_in = z_buffer;
+  z->avail_in = z_length;
+
+  buffer = g_malloc(length);
+  ret = inflateInit(z);
+  while(z->avail_in > 0){
+    if(z->avail_out == 0){
+      length += 1024;
+      buffer = realloc(buffer, length);
+      z->next_out = buffer + z->total_out;
+      z->avail_out = 1024;
+    }
+    ret = inflate(z,Z_SYNC_FLUSH);
+    if(ret != Z_OK)break;
+  }
+  if(ret != Z_STREAM_END){
+    g_warning("inflate() returned %d\n",ret);
+  }
+
+  g_free(z);
+  return buffer;
+}
 
 static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length)
 {
+  GNode *cmov;
 
   qtdemux->moov_node = g_node_new(buffer);
 
   qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length);
 
+  cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov);
+  if(cmov){
+    GNode *dcom;
+    GNode *cmvd;
+
+    dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom);
+    cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd);
+
+    if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){
+      int uncompressed_length;
+      int compressed_length;
+      void *buf;
+      
+      uncompressed_length = QTDEMUX_GUINT32_GET(cmvd->data+8);
+      compressed_length = QTDEMUX_GUINT32_GET(cmvd->data+4) - 12;
+      g_print("length = %d\n",uncompressed_length);
+
+      buf = qtdemux_inflate(cmvd->data + 12, compressed_length,
+         uncompressed_length);
+
+      qtdemux->moov_node_compressed = qtdemux->moov_node;
+      qtdemux->moov_node = g_node_new(buf);
+
+      qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length);
+    }else{
+      g_print("unknown header compression type\n");
+    }
+  }
 }
 
 static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length)
@@ -661,8 +810,8 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le
 
   //g_print("qtdemux_parse %p %d\n",buffer, length);
 
-  node_length = GUINT32_FROM_BE(*(guint32 *)buffer);
-  fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4));
+  node_length = QTDEMUX_GUINT32_GET(buffer);
+  fourcc = QTDEMUX_FOURCC_GET(buffer+4);
 
   type = qtdemux_type_get(fourcc);
   
@@ -682,7 +831,7 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le
        /* FIXME: get annoyed */
        g_print("buffer overrun\n");
       }
-      len = GUINT32_FROM_BE(*(guint32 *)buf);
+      len = QTDEMUX_GUINT32_GET(buf);
 
       child = g_node_new(buf);
       g_node_append(node, child);
@@ -691,8 +840,35 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le
       buf += len;
     }
   }else{
-    //g_print("not container\n");
+#if 0
+    if(fourcc == FOURCC_cmvd){
+      int uncompressed_length;
+      void *buf;
+      
+      uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8);
+      g_print("length = %d\n",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 */
+         g_print("buffer overrun\n");
+        }
+        len = QTDEMUX_GUINT32_GET(buf);
 
+        child = g_node_new(buf);
+        g_node_append(node, child);
+        qtdemux_parse(qtdemux, child, buf, len);
+
+        buf += len;
+      }
+    }
+#endif
   }
 }
 
@@ -738,15 +914,6 @@ static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node)
       qtdemux_node_dump_foreach, qtdemux);
 }
 
-#define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a))
-#define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a))
-#define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a))
-#define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0)
-#define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0)
-#define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a))
-
-#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4))
-
 static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth)
 {
   g_print("%*s  version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
@@ -993,6 +1160,17 @@ static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth)
   }
 }
 
+static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth)
+{
+  g_print("%*s  compression type: " GST_FOURCC_FORMAT "\n", depth, "",
+      GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+8)));
+}
+
+static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth)
+{
+  g_print("%*s  length: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8));
+}
+
 
 static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc)
 {
@@ -1038,6 +1216,10 @@ static void qtdemux_parse_tree(GstQTDemux *qtdemux)
   GNode *trak;
 
   mvhd = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_mvhd);
+  if(mvhd==NULL){
+    g_print("No mvhd node found.\n");
+    return;
+  }
 
   qtdemux->timescale = QTDEMUX_GUINT32_GET(mvhd->data + 20);
   qtdemux->duration = QTDEMUX_GUINT32_GET(mvhd->data + 24);
@@ -1085,20 +1267,13 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
 
   /* track duration? */
 
-  //g_print("track duration: %u\n", QTDEMUX_GUINT32_GET(buffer+28));
-  g_print("track width:   %g\n", QTDEMUX_FP32_GET(tkhd->data+84));
-  g_print("track height:  %g\n", QTDEMUX_FP32_GET(tkhd->data+88));
-
   mdia = qtdemux_tree_get_child_by_type(trak, FOURCC_mdia);
   g_assert(mdia);
 
   mdhd = qtdemux_tree_get_child_by_type(mdia, FOURCC_mdhd);
   g_assert(mdhd);
 
-  g_print("track time scale: %d\n", QTDEMUX_GUINT32_GET(mdhd->data+20));
   stream->timescale = QTDEMUX_GUINT32_GET(mdhd->data+20);
-  //g_print("track height:  %g\n", QTDEMUX_FP32_GET(mdhd->data+88));
   
   hdlr = qtdemux_tree_get_child_by_type(mdia, FOURCC_hdlr);
   g_assert(hdlr);
@@ -1124,34 +1299,38 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
     g_print("st type:          " GST_FOURCC_FORMAT "\n",
          GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+offset+4)));
 
-    g_print("width:         %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+32));
-    g_print("height:        %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+34));
-
-    //g_print("data size:     %u\n", QTDEMUX_GUINT32_GET(stsd->data+offset+44));
-    //g_print("frame count:   %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48));
+    stream->width = QTDEMUX_GUINT16_GET(stsd->data+offset+32);
+    stream->height = QTDEMUX_GUINT16_GET(stsd->data+offset+34);
 
-    //g_print("compressor:    %*s\n", QTDEMUX_GUINT8_GET(stsd->data+offset+49), (char *)(stsd->data+offset+51));
+    g_print("frame count:   %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48));
     
     stream->caps = qtdemux_video_caps(qtdemux,
         QTDEMUX_FOURCC_GET(stsd->data+offset+4));
     g_print("caps %s\n",gst_caps_to_string(stream->caps));
   }else if(stream->subtype == FOURCC_soun){
+    int version;
+
     g_print("st type:          " GST_FOURCC_FORMAT "\n",
          GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4)));
 
     offset = 32;
     g_print("version/rev:      %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset));
+    version = QTDEMUX_GUINT32_GET(stsd->data+offset);
     g_print("vendor:           %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4));
     g_print("n_channels:       %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 8));
+    stream->n_channels = QTDEMUX_GUINT16_GET(stsd->data+offset + 8);
     g_print("sample_size:      %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 10));
     g_print("compression_id:   %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 12));
     g_print("packet size:      %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 14));
-    g_print("sample rate:      %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 16));
-
-    g_print("samples/packet:   %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20));
-    g_print("bytes/packet:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24));
-    g_print("bytes/frame:      %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28));
-    g_print("bytes/sample:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32));
+    g_print("sample rate:      %g\n", QTDEMUX_FP32_GET(stsd->data+offset + 16));
+    stream->rate = QTDEMUX_FP32_GET(stsd->data+offset + 16);
+
+    if(version == 0x00010000){
+      g_print("samples/packet:   %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20));
+      g_print("bytes/packet:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24));
+      g_print("bytes/frame:      %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28));
+      g_print("bytes/sample:     %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32));
+    }
 
     stream->caps = qtdemux_audio_caps(qtdemux,
         QTDEMUX_FOURCC_GET(stsd->data+16+4));
@@ -1161,6 +1340,11 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak)
     return;
   }
 
+  if(stream->caps){
+    gst_caps_ref(stream->caps);
+    gst_caps_sink(stream->caps);
+  }
+
   /* sample to chunk */
   stsc = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsc);
   g_assert(stsc);
@@ -1236,6 +1420,8 @@ done:
       }
     }
   }else{
+    int sample_width;
+
     g_print("treating chunks as samples\n");
 
     /* treat chunks as samples */
@@ -1248,6 +1434,8 @@ done:
     samples = g_malloc(sizeof(QtDemuxSample)*n_samples);
     stream->samples = samples;
 
+    sample_width = QTDEMUX_GUINT16_GET(stsd->data+offset + 10) / 8;
+
     n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12);
     offset = 16;
     sample_index = 0;
@@ -1272,7 +1460,7 @@ done:
         }
        samples[j].chunk = j;
        samples[j].offset = chunk_offset;
-       samples[j].size = samples_per_chunk; /* FIXME */
+       samples[j].size = samples_per_chunk * stream->n_channels * sample_width;
        samples[j].sample_index = sample_index;
        sample_index += samples_per_chunk;
        if(j>=n_samples)goto done2;
@@ -1302,13 +1490,14 @@ done2:
     }
   }
 
-
+#if 0
   for(i=0;i<n_samples;i++){
     g_print("%d: %d %d %d %d %" G_GUINT64_FORMAT "\n",i,
        samples[i].sample_index,samples[i].chunk,
        samples[i].offset, samples[i].size, samples[i].timestamp);
     if(i>10)break;
   }
+#endif
 
   gst_qtdemux_add_stream(qtdemux,stream);
 }
@@ -1322,10 +1511,10 @@ static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc)
       return GST_CAPS_NEW("jpeg_caps","video/jpeg",NULL);
     case GST_MAKE_FOURCC('m','j','p','a'):
       /* Motion-JPEG (format A) */
-      return GST_CAPS_NEW("mjpa_caps","video/x-mjpeg",NULL);
+      return GST_CAPS_NEW("mjpa_caps","video/jpeg",NULL);
     case GST_MAKE_FOURCC('m','j','p','b'):
       /* Motion-JPEG (format B) */
-      return GST_CAPS_NEW("mjpa_caps","video/x-mjpeg",NULL);
+      return GST_CAPS_NEW("mjpa_caps","video/jpeg",NULL);
     case GST_MAKE_FOURCC('S','V','Q','3'):
       return GST_CAPS_NEW("SVQ3_caps","video/x-svq",
          "svqversion", GST_PROPS_INT(3),NULL);
@@ -1350,17 +1539,24 @@ static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc)
       return GST_CAPS_NEW("mpeg_caps","video/mpeg",NULL);
     case GST_MAKE_FOURCC('g','i','f',' '):
       return GST_CAPS_NEW("gif__caps","image/gif",NULL);
+    case GST_MAKE_FOURCC('h','2','6','3'):
+      /* H.263 */
+      /* ffmpeg uses the height/width props, don't know why */
+      return GST_CAPS_NEW("h263_caps","video/h263",
+         "width",GST_PROPS_INT_RANGE(1,G_MAXINT),
+         "height",GST_PROPS_INT_RANGE(1,G_MAXINT));
     case GST_MAKE_FOURCC('m','p','4','v'):
       /* MPEG-4 */
-      return NULL;
-      //return GST_CAPS_NEW("mp4v_caps", "video/mpeg",NULL);
+      return GST_CAPS_NEW("mp4v_caps", "video/mpeg",
+         "mpegversion",GST_PROPS_INT(4));
+    case GST_MAKE_FOURCC('3','I','V','1'):
+      return GST_CAPS_NEW("3IV1_caps", "video/3ivx",NULL);
     case GST_MAKE_FOURCC('r','p','z','a'):
     case GST_MAKE_FOURCC('c','v','i','d'):
       /* Cinepak */
     case GST_MAKE_FOURCC('r','l','e',' '):
     case GST_MAKE_FOURCC('s','m','c',' '):
     case GST_MAKE_FOURCC('k','p','c','d'):
-    case GST_MAKE_FOURCC('3','I','V','1'):
     default:
       g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT
          "' to caps\n", GST_FOURCC_ARGS(fourcc));
@@ -1467,16 +1663,16 @@ static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc)
       /* DV audio */
     case GST_MAKE_FOURCC('q','t','v','r'):
       /* ? */
-    case GST_MAKE_FOURCC('Q','D','M','C'):
-      /* QDesign music */
     case GST_MAKE_FOURCC('Q','D','M','2'):
       /* QDesign music version 2 (no constant) */
+    case GST_MAKE_FOURCC('Q','D','M','C'):
+      /* QDesign music */
     case GST_MAKE_FOURCC('M','A','C','3'):
       /* MACE 3:1 */
     case GST_MAKE_FOURCC('M','A','C','6'):
       /* MACE 6:1 */
     case GST_MAKE_FOURCC('i','m','a','4'):
-      /* ? */
+      /* IMA 4:1 */
     case GST_MAKE_FOURCC('Q','c','l','p'):
       /* QUALCOMM PureVoice */
     default:
index 53af27b7f712702e19062e753b12aa04e5410caf..108faab19669fc5451177ec4f7e067303f117514 100644 (file)
@@ -60,12 +60,15 @@ struct _GstQTDemux {
   GstByteStream *bs;
 
   GNode *moov_node;
+  GNode *moov_node_compressed;
 
   guint32 timescale;
   guint32 duration;
 
   int state;
 
+  int offset;
+
   /* track stuff */
 
 };