isomp4: fsync after sending updates in robust mode
authorJan Schmidt <jan@centricular.com>
Thu, 16 Apr 2015 00:44:49 +0000 (10:44 +1000)
committerJan Schmidt <jan@centricular.com>
Mon, 8 Jun 2015 04:49:11 +0000 (14:49 +1000)
Use the new GstBuffer SYNC_AFTER flag to trigger an fsync
after updating the moov or mdat atom, and after updating the free
atom to make it visible.

gst/isomp4/gstqtmux.c

index 7fd1eb63c701b8c15af2474e6f8485b619037f25..34eb4ae30441b950fc115186e1a224e2f0665039 100644 (file)
@@ -1543,7 +1543,7 @@ fail:
  */
 static GstFlowReturn
 gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
-    gboolean extended)
+    gboolean extended, gboolean fsync_after)
 {
   GstBuffer *buf;
   GstMapInfo map;
@@ -1587,6 +1587,9 @@ gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
   }
 
   GST_LOG_OBJECT (qtmux, "Pushing mdat header");
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
+
   return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
 
 }
@@ -1597,7 +1600,7 @@ gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
  */
 static GstFlowReturn
 gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
-    guint64 mdat_size, guint64 * offset)
+    guint64 mdat_size, guint64 * offset, gboolean fsync_after)
 {
   GstSegment segment;
 
@@ -1609,7 +1612,8 @@ gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos,
   segment.start = mdat_pos;
   gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
 
-  return gst_qt_mux_send_mdat_header (qtmux, offset, mdat_size, TRUE);
+  return gst_qt_mux_send_mdat_header (qtmux, offset, mdat_size, TRUE,
+      fsync_after);
 }
 
 static GstFlowReturn
@@ -1721,7 +1725,8 @@ gst_qt_mux_set_header_on_caps (GstQTMux * mux, GstBuffer * buf)
  * size, but a smaller buffer is sent
  */
 static GstFlowReturn
-gst_qt_mux_send_free_atom (GstQTMux * qtmux, guint64 * off, guint32 size)
+gst_qt_mux_send_free_atom (GstQTMux * qtmux, guint64 * off, guint32 size,
+    gboolean fsync_after)
 {
   Atom *node_header;
   GstBuffer *buf;
@@ -1746,6 +1751,9 @@ gst_qt_mux_send_free_atom (GstQTMux * qtmux, guint64 * off, guint32 size)
   buf = _gst_buffer_new_take_data (data, offset);
   g_free (node_header);
 
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
+
   GST_LOG_OBJECT (qtmux, "Pushing free atom");
   ret = gst_qt_mux_send_buffer (qtmux, buf, off, FALSE);
 
@@ -1804,7 +1812,7 @@ gst_qt_mux_configure_moov (GstQTMux * qtmux)
 
 static GstFlowReturn
 gst_qt_mux_send_moov (GstQTMux * qtmux, guint64 * _offset,
-    guint64 padded_moov_size, gboolean mind_fast)
+    guint64 padded_moov_size, gboolean mind_fast, gboolean fsync_after)
 {
   guint64 offset = 0, size = 0;
   guint8 *data;
@@ -1829,13 +1837,18 @@ gst_qt_mux_send_moov (GstQTMux * qtmux, guint64 * _offset,
    * (apparently used by a flumotion util) */
   if (qtmux->state == GST_QT_MUX_STATE_EOS)
     gst_qt_mux_set_header_on_caps (qtmux, buf);
+
+  if (fsync_after)
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_SYNC_AFTER);
   ret = gst_qt_mux_send_buffer (qtmux, buf, _offset, mind_fast);
 
   /* Write out a free atom if needed */
   if (ret == GST_FLOW_OK && offset < padded_moov_size) {
     GST_LOG_OBJECT (qtmux, "Writing out free atom of size %u",
         (guint32) (padded_moov_size - offset));
-    ret = gst_qt_mux_send_free_atom (qtmux, _offset, padded_moov_size - offset);
+    ret =
+        gst_qt_mux_send_free_atom (qtmux, _offset, padded_moov_size - offset,
+        fsync_after);
   }
 
   return ret;
@@ -2077,7 +2090,9 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       qtmux->mdat_pos = qtmux->header_size;
       /* extended atom in case we go over 4GB while writing and need
        * the full 64-bit atom */
-      ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE);
+      ret =
+          gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE,
+          FALSE);
       break;
     case GST_QT_MUX_MODE_ROBUST_RECORDING:
 
@@ -2094,7 +2109,9 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
         /* Extra 8 bytes for the padding free atom header */
         guint padding = (guint) (16 - (qtmux->header_size % 8));
         GST_LOG_OBJECT (qtmux, "Rounding ftyp by %u bytes", padding);
-        ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, padding);
+        ret =
+            gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, padding,
+            FALSE);
         if (ret != GST_FLOW_OK)
           return ret;
       }
@@ -2109,11 +2126,11 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       gst_qt_mux_configure_moov (qtmux);
       gst_qt_mux_setup_metadata (qtmux);
       /* Empty free atom to begin, starting on an 8-byte boundary */
-      ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, 8);
+      ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size, 8, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
       /* Moov header, not padded yet */
-      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE);
+      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
       /* The moov we just sent contains the 'base' size of the moov, before
@@ -2148,14 +2165,14 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       /* Now that we know how much reserved space is targetted,
        * output a free atom to fill the extra reserved */
       ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
-          qtmux->reserved_moov_size - qtmux->base_moov_size);
+          qtmux->reserved_moov_size - qtmux->base_moov_size, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
 
       /* Then a free atom containing 'pong' buffer, with an
        * extra 8 bytes to account for the free atom header itself */
       ret = gst_qt_mux_send_free_atom (qtmux, &qtmux->header_size,
-          qtmux->reserved_moov_size + 8);
+          qtmux->reserved_moov_size + 8, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
 
@@ -2168,7 +2185,9 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       qtmux->mdat_pos = qtmux->header_size;
       /* extended atom in case we go over 4GB while writing and need
        * the full 64-bit atom */
-      ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE);
+      ret =
+          gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE,
+          FALSE);
       break;
     case GST_QT_MUX_MODE_FAST_START:
       GST_OBJECT_LOCK (qtmux);
@@ -2195,7 +2214,7 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
       /* prepare moov and/or tags */
       gst_qt_mux_configure_moov (qtmux);
       gst_qt_mux_setup_metadata (qtmux);
-      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE);
+      ret = gst_qt_mux_send_moov (qtmux, &qtmux->header_size, 0, FALSE, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
       /* extra atoms */
@@ -2432,7 +2451,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
       segment.start = qtmux->moov_pos;
       gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
       /* no need to seek back */
-      return gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE);
+      return gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE, FALSE);
     }
     case GST_QT_MUX_MODE_ROBUST_RECORDING:{
       ret = gst_qt_mux_robust_recording_rewrite_moov (qtmux);
@@ -2442,7 +2461,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
        * it's been 0, which means 'rest of the file'
        * No need to seek back after this, we won't write any more */
       return gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
-          qtmux->mdat_size, NULL);
+          qtmux->mdat_size, NULL, TRUE);
     }
     default:
       break;
@@ -2494,7 +2513,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
   /* write out moov and extra atoms */
   /* note: as of this point, we no longer care about tracking written data size,
    * since there is no more use for it anyway */
-  ret = gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE);
+  ret = gst_qt_mux_send_moov (qtmux, NULL, 0, FALSE, FALSE);
   if (ret != GST_FLOW_OK)
     return ret;
 
@@ -2509,7 +2528,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
       /* mdat needs update iff not using faststart */
       GST_DEBUG_OBJECT (qtmux, "updating mdat size");
       ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
-          qtmux->mdat_size, NULL);
+          qtmux->mdat_size, NULL, FALSE);
       /* note; no seeking back to the end of file is done,
        * since we no longer write anything anyway */
       break;
@@ -2519,7 +2538,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
       /* send mdat atom and move buffered data into it */
       /* mdat_size = accumulated (buffered data) */
       ret = gst_qt_mux_send_mdat_header (qtmux, NULL, qtmux->mdat_size,
-          large_file);
+          large_file, FALSE);
       if (ret != GST_FLOW_OK)
         return ret;
       ret = gst_qt_mux_send_buffered_data (qtmux, NULL);
@@ -2594,7 +2613,7 @@ flush:
         atom_array_get_len (&pad->fragment_buffers), total_size);
     if (ret == GST_FLOW_OK)
       ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, total_size,
-          FALSE);
+          FALSE, FALSE);
     for (i = 0; i < atom_array_get_len (&pad->fragment_buffers); i++) {
       if (G_LIKELY (ret == GST_FLOW_OK))
         ret = gst_qt_mux_send_buffer (qtmux,
@@ -2709,7 +2728,9 @@ gst_qt_mux_robust_recording_rewrite_moov (GstQTMux * qtmux)
   segment.start = new_moov_offset;
   gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
 
-  ret = gst_qt_mux_send_moov (qtmux, NULL, qtmux->reserved_moov_size, FALSE);
+  ret =
+      gst_qt_mux_send_moov (qtmux, NULL, qtmux->reserved_moov_size, FALSE,
+      TRUE);
   if (ret != GST_FLOW_OK)
     return ret;
 
@@ -2753,7 +2774,7 @@ gst_qt_mux_robust_recording_rewrite_moov (GstQTMux * qtmux)
   segment.start = freeA_offset;
   gst_pad_push_event (qtmux->srcpad, gst_event_new_segment (&segment));
 
-  ret = gst_qt_mux_send_free_atom (qtmux, NULL, new_freeA_size);
+  ret = gst_qt_mux_send_free_atom (qtmux, NULL, new_freeA_size, TRUE);
 
   return ret;
 }