mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
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.
This commit is contained in:
parent
99f47c4b17
commit
e8c21f14cc
1 changed files with 120 additions and 86 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue