isomp4: fsync after sending updates in robust mode

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.
This commit is contained in:
Jan Schmidt 2015-04-16 10:44:49 +10:00
parent 3e17cd8acb
commit 23d610140d

View file

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