From e8c21f14cc802c3fb427424e7190f55d298f33d3 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 15 Oct 2009 21:11:16 -0300 Subject: [PATCH] qtmux: Only push ftyp later (in faststart mode) In faststart mode, there is no need to send the ftyp right at the beginning of the stream. Waiting and sending it only later (when the moov atom is ready to be sent) provides us with more information about the stream and we can better select the compatible brands. --- gst/quicktime/gstqtmux.c | 206 +++++++++++++++++++++++---------------- 1 file changed, 120 insertions(+), 86 deletions(-) diff --git a/gst/quicktime/gstqtmux.c b/gst/quicktime/gstqtmux.c index 1582d9c84e..2ed0cea98d 100644 --- a/gst/quicktime/gstqtmux.c +++ b/gst/quicktime/gstqtmux.c @@ -992,6 +992,115 @@ gst_qt_mux_update_mdat_size (GstQTMux * qtmux, guint64 mdat_pos, return gst_qt_mux_send_buffer (qtmux, buf, offset, FALSE); } +static GstFlowReturn +gst_qt_mux_send_ftyp (GstQTMux * qtmux, guint64 * off) +{ + GstBuffer *buf; + guint64 size = 0, offset = 0; + guint8 *data = NULL; + + GST_DEBUG_OBJECT (qtmux, "Sending ftyp atom"); + + if (!atom_ftyp_copy_data (qtmux->ftyp, &data, &size, &offset)) + goto serialize_error; + + buf = gst_buffer_new (); + GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data; + GST_BUFFER_SIZE (buf) = offset; + + GST_LOG_OBJECT (qtmux, "Pushing ftyp"); + return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE); + + /* ERRORS */ +serialize_error: + { + GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), + ("Failed to serialize ftyp")); + return GST_FLOW_ERROR; + } +} + +static GstFlowReturn +gst_qt_mux_prepare_and_send_ftyp (GstQTMux * qtmux) +{ + GstFlowReturn ret = GST_FLOW_OK; + GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux)); + guint32 major, version; + GList *comp; + GstBuffer *prefix; + + GST_DEBUG_OBJECT (qtmux, "Preparing to send ftyp atom"); + + /* init and send context and ftyp based on current property state */ + if (qtmux->ftyp) + atom_ftyp_free (qtmux->ftyp); + gst_qt_mux_map_format_to_header (qtmux_klass->format, &prefix, &major, + &version, &comp, qtmux->moov); + qtmux->ftyp = atom_ftyp_new (qtmux->context, major, version, comp); + if (comp) + g_list_free (comp); + if (prefix) { + ret = gst_qt_mux_send_buffer (qtmux, prefix, &qtmux->header_size, FALSE); + if (ret != GST_FLOW_OK) + return ret; + } + return gst_qt_mux_send_ftyp (qtmux, &qtmux->header_size); +} + +static GstFlowReturn +gst_qt_mux_start_file (GstQTMux * qtmux) +{ + GstFlowReturn ret = GST_FLOW_OK; + + GST_DEBUG_OBJECT (qtmux, "starting file"); + + /* let downstream know we think in BYTES and expect to do seeking later on */ + gst_pad_push_event (qtmux->srcpad, + gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)); + + /* + * send mdat header if already needed, and mark position for later update. + * We don't send ftyp now if we are on fast start mode, because we can + * better fine tune using the information we gather to create the whole moov + * atom. + */ + if (qtmux->fast_start) { + GST_OBJECT_LOCK (qtmux); + qtmux->fast_start_file = g_fopen (qtmux->fast_start_file_path, "wb+"); + if (!qtmux->fast_start_file) + goto open_failed; + GST_OBJECT_UNLOCK (qtmux); + + /* send a dummy buffer for preroll */ + ret = gst_qt_mux_send_buffer (qtmux, gst_buffer_new (), NULL, FALSE); + if (ret != GST_FLOW_OK) + goto exit; + + } else { + ret = gst_qt_mux_prepare_and_send_ftyp (qtmux); + if (ret != GST_FLOW_OK) { + goto exit; + } + + /* extended to ensure some spare space */ + qtmux->mdat_pos = qtmux->header_size; + ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE); + } + +exit: + return ret; + + /* ERRORS */ +open_failed: + { + GST_ELEMENT_ERROR (qtmux, RESOURCE, OPEN_READ_WRITE, + (("Could not open temporary file \"%s\""), qtmux->fast_start_file_path), + GST_ERROR_SYSTEM); + GST_OBJECT_UNLOCK (qtmux); + return GST_FLOW_ERROR; + } +} + static GstFlowReturn gst_qt_mux_stop_file (GstQTMux * qtmux) { @@ -1040,10 +1149,17 @@ gst_qt_mux_stop_file (GstQTMux * qtmux) large_file = (qtmux->mdat_size > MDAT_LARGE_FILE_LIMIT); /* if faststart, update the offset of the atoms in the movie with the offset - * that the movie headers before mdat will cause */ + * that the movie headers before mdat will cause. + * Also, send the ftyp */ if (qtmux->fast_start_file) { - /* copy into NULL to obtain size */ + GstFlowReturn flow_ret; offset = size = 0; + + flow_ret = gst_qt_mux_prepare_and_send_ftyp (qtmux); + if (flow_ret != GST_FLOW_OK) { + goto ftyp_error; + } + /* copy into NULL to obtain size */ if (!atom_moov_copy_data (qtmux->moov, NULL, &size, &offset)) goto serialize_error; GST_DEBUG_OBJECT (qtmux, "calculated moov atom size %" G_GUINT64_FORMAT, @@ -1098,91 +1214,9 @@ serialize_error: ("Failed to serialize moov")); return GST_FLOW_ERROR; } -} - -static GstFlowReturn -gst_qt_mux_send_ftyp (GstQTMux * qtmux, guint64 * off) -{ - GstBuffer *buf; - guint64 size = 0, offset = 0; - guint8 *data = NULL; - - GST_DEBUG_OBJECT (qtmux, "Sending ftyp atom"); - - if (!atom_ftyp_copy_data (qtmux->ftyp, &data, &size, &offset)) - goto serialize_error; - - buf = gst_buffer_new (); - GST_BUFFER_DATA (buf) = GST_BUFFER_MALLOCDATA (buf) = data; - GST_BUFFER_SIZE (buf) = offset; - - GST_LOG_OBJECT (qtmux, "Pushing ftyp"); - return gst_qt_mux_send_buffer (qtmux, buf, off, FALSE); - - /* ERRORS */ -serialize_error: +ftyp_error: { - GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), - ("Failed to serialize ftyp")); - return GST_FLOW_ERROR; - } -} - -static GstFlowReturn -gst_qt_mux_start_file (GstQTMux * qtmux) -{ - GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux)); - GstFlowReturn ret = GST_FLOW_OK; - guint32 major, version; - GList *comp; - GstBuffer *prefix; - - GST_DEBUG_OBJECT (qtmux, "starting file"); - - /* let downstream know we think in BYTES and expect to do seeking later on */ - gst_pad_push_event (qtmux->srcpad, - gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0)); - - /* init and send context and ftyp based on current property state */ - if (qtmux->ftyp) - atom_ftyp_free (qtmux->ftyp); - gst_qt_mux_map_format_to_header (qtmux_klass->format, &prefix, &major, - &version, &comp, qtmux->moov); - qtmux->ftyp = atom_ftyp_new (qtmux->context, major, version, comp); - if (comp) - g_list_free (comp); - if (prefix) { - ret = gst_qt_mux_send_buffer (qtmux, prefix, &qtmux->header_size, FALSE); - if (ret != GST_FLOW_OK) - goto exit; - } - ret = gst_qt_mux_send_ftyp (qtmux, &qtmux->header_size); - if (ret != GST_FLOW_OK) - goto exit; - - /* send mdat header if already needed, and mark position for later update */ - GST_OBJECT_LOCK (qtmux); - if (qtmux->fast_start) { - qtmux->fast_start_file = g_fopen (qtmux->fast_start_file_path, "wb+"); - if (!qtmux->fast_start_file) - goto open_failed; - } else { - /* extended to ensure some spare space */ - qtmux->mdat_pos = qtmux->header_size; - ret = gst_qt_mux_send_mdat_header (qtmux, &qtmux->header_size, 0, TRUE); - } - GST_OBJECT_UNLOCK (qtmux); - -exit: - return ret; - - /* ERRORS */ -open_failed: - { - GST_ELEMENT_ERROR (qtmux, RESOURCE, OPEN_READ_WRITE, - (("Could not open temporary file \"%s\""), qtmux->fast_start_file_path), - GST_ERROR_SYSTEM); - GST_OBJECT_UNLOCK (qtmux); + GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL), ("Failed to send ftyp")); return GST_FLOW_ERROR; } }