gst/qtdemux/qtdemux.*: Make push-based work if mdat atom is before moov atom.
authorEdward Hervey <bilboed@bilboed.com>
Tue, 14 Feb 2006 18:50:13 +0000 (18:50 +0000)
committerEdward Hervey <bilboed@bilboed.com>
Tue, 14 Feb 2006 18:50:13 +0000 (18:50 +0000)
Original commit message from CVS:
* gst/qtdemux/qtdemux.c: (gst_qtdemux_init),
(gst_qtdemux_handle_src_query), (gst_qtdemux_change_state),
(next_entry_size), (gst_qtdemux_chain):
* gst/qtdemux/qtdemux.h:
Make push-based work if mdat atom is before moov atom.
Don't answer duration query. This should be transformed into replying
FALSE to seek events.

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

index 204933792d12c4377e02cc1b9c46a79f32df4e23..77a0c5d1453db4c1adaa3005deed360317a444a7 100644 (file)
@@ -104,6 +104,7 @@ enum QtDemuxState
   QTDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
   QTDEMUX_STATE_HEADER,         /* Parsing the header */
   QTDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
+  QTDEMUX_STATE_BUFFER_MDAT,    /* Buffering the mdat atom */
 };
 
 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
@@ -242,6 +243,9 @@ gst_qtdemux_init (GstQTDemux * qtdemux)
   qtdemux->neededbytes = 16;
   qtdemux->todrop = 0;
   qtdemux->adapter = gst_adapter_new ();
+  qtdemux->offset = 0;
+  qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
+  qtdemux->mdatbuffer = NULL;
 }
 
 #if 0
@@ -324,7 +328,8 @@ gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
       }
       break;
     case GST_QUERY_DURATION:
-      if (qtdemux->duration != 0 && qtdemux->timescale != 0) {
+      if (qtdemux->pullbased && qtdemux->duration != 0
+          && qtdemux->timescale != 0) {
         gint64 duration;
 
         duration = gst_util_uint64_scale_int (qtdemux->duration,
@@ -498,6 +503,10 @@ gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
       qtdemux->todrop = 0;
       qtdemux->pullbased = FALSE;
       qtdemux->offset = 0;
+      qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
+      if (qtdemux->mdatbuffer)
+        gst_buffer_unref (qtdemux->mdatbuffer);
+      qtdemux->mdatbuffer = NULL;
       gst_adapter_clear (qtdemux->adapter);
       for (n = 0; n < qtdemux->n_streams; n++) {
         gst_element_remove_pad (element, qtdemux->streams[n]->pad);
@@ -775,8 +784,9 @@ next_entry_size (GstQTDemux * demux)
         stream->samples[stream->sample_index].size,
         stream->samples[stream->sample_index].chunk);
 
-    if ((smalloffs == -1)
-        || (stream->samples[stream->sample_index].offset < smalloffs)) {
+    if (((smalloffs == -1)
+            || (stream->samples[stream->sample_index].offset < smalloffs))
+        && (stream->samples[stream->sample_index].size)) {
       smallidx = i;
       smalloffs = stream->samples[stream->sample_index].offset;
     }
@@ -812,7 +822,7 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
       inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
 
   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
-      ret == GST_FLOW_OK) {
+      (ret == GST_FLOW_OK)) {
 
     GST_DEBUG_OBJECT (demux,
         "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
@@ -832,16 +842,14 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
             "Peeking found [%" GST_FOURCC_FORMAT "] size:%ld",
             GST_FOURCC_ARGS (fourcc), size);
         if ((fourcc == GST_MAKE_FOURCC ('m', 'd', 'a', 't'))) {
-          if (demux->n_streams <= 0) {
-            GST_ELEMENT_ERROR (demux, STREAM, FAILED,
-                (NULL),
-                ("Can't handled files with header after data in push-mode!"));
-            ret = GST_FLOW_ERROR;
+          if (demux->n_streams > 0) {
+            demux->state = QTDEMUX_STATE_MOVIE;
+            demux->neededbytes = next_entry_size (demux);
+          } else {
+            demux->state = QTDEMUX_STATE_BUFFER_MDAT;
+            demux->neededbytes = size;
+            demux->mdatoffset = demux->offset;
           }
-          demux->state = QTDEMUX_STATE_MOVIE;
-          demux->offset += 24;
-          gst_adapter_flush (demux->adapter, 24);
-          demux->neededbytes = next_entry_size (demux);
         } else {
           demux->neededbytes = size;
           demux->state = QTDEMUX_STATE_HEADER;
@@ -862,7 +870,6 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
         if (fourcc == GST_MAKE_FOURCC ('m', 'o', 'o', 'v')) {
           GST_DEBUG_OBJECT (demux, "Parsing [moov]");
 
-          demux->offset += demux->neededbytes;
           qtdemux_parse_moov (demux, data, demux->neededbytes);
           qtdemux_node_dump (demux, demux->moov_node);
           qtdemux_parse_tree (demux);
@@ -870,14 +877,28 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
           g_node_destroy (demux->moov_node);
           g_free (data);
           demux->moov_node = NULL;
-
-          demux->neededbytes = 16;
-          demux->state = QTDEMUX_STATE_INITIAL;
         } else {
           GST_WARNING_OBJECT (demux,
               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
               GST_FOURCC_ARGS (fourcc));
           /* Let's jump that one and go back to initial state */
+        }
+
+        GST_DEBUG_OBJECT (demux, "Finished parsing the header");
+        if (demux->mdatbuffer && demux->n_streams) {
+          /* the mdat was before the header */
+          GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
+              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_adapter_push (demux->adapter, demux->mdatbuffer);
+          demux->mdatbuffer = NULL;
+          demux->offset = demux->mdatoffset;
+          demux->neededbytes = next_entry_size (demux);
+          demux->state = QTDEMUX_STATE_MOVIE;
+        } else {
+          GST_DEBUG_OBJECT (demux, "Carrying on normally");
           demux->offset += demux->neededbytes;
           demux->neededbytes = 16;
           demux->state = QTDEMUX_STATE_INITIAL;
@@ -885,6 +906,23 @@ gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
       }
         break;
 
+      case QTDEMUX_STATE_BUFFER_MDAT:{
+        GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
+            demux->mdatoffset);
+        if (demux->mdatbuffer)
+          gst_buffer_unref (demux->mdatbuffer);
+        demux->mdatbuffer = gst_buffer_new ();
+        gst_buffer_set_data (demux->mdatbuffer,
+            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)));
+        demux->offset += demux->neededbytes;
+        demux->neededbytes = 16;
+        demux->state = QTDEMUX_STATE_INITIAL;
+      }
+        break;
+
       case QTDEMUX_STATE_MOVIE:{
         guint8 *data;
         GstBuffer *outbuf;
index 42aa1571d277b9f91ea4aa87d5c35e283836eb01..97b907f99c0f5abae5b143ab7845af3e23dd114d 100644 (file)
@@ -68,9 +68,12 @@ struct _GstQTDemux {
   guint neededbytes;
   guint todrop;
   GstAdapter *adapter;
+  GstBuffer *mdatbuffer;
 
   /* offset of the media data (i.e.: Size of header) */
   guint64 offset;
+  /* offset of the mdat atom */
+  guint64 mdatoffset;
 
   GstTagList *tag_list;