Commit b692f9ff authored by Thiago Santos's avatar Thiago Santos Committed by Tim-Philipp Müller

qtmux: Adds moov recovery feature

Adds a new property to qtmux that sets a path to a file to write
and update data about the moov atom (that is not writen till the
end of the file). If the pipeline/app crashes during execution it
might be possible to recover the movie using the qtmoovrecover element.

qtmoovrecover is an element that is also a pipeline. It is not
meant to be used with other elements (it has no pads). It is merely
a tool/utilitary to recover unfinished qtmux files.

Fixes #601576
parent 3c0e4d82
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
*
* This library is free software; you can redistribute it and/or
......@@ -49,38 +49,6 @@
#include <gst/base/gstbytewriter.h>
/* storage helpers */
#define atom_array_init(array, reserve) \
G_STMT_START { \
(array)->len = 0; \
(array)->size = reserve; \
(array)->data = g_malloc (sizeof (*(array)->data) * reserve); \
} G_STMT_END
#define atom_array_append(array, elmt, inc) \
G_STMT_START { \
g_assert ((array)->data); \
g_assert (inc > 0); \
if (G_UNLIKELY ((array)->len == (array)->size)) { \
(array)->size += inc; \
(array)->data = \
g_realloc ((array)->data, sizeof (*((array)->data)) * (array)->size); \
} \
(array)->data[(array)->len] = elmt; \
(array)->len++; \
} G_STMT_END
#define atom_array_get_len(array) ((array)->len)
#define atom_array_index(array, index) ((array)->data[index])
#define atom_array_clear(array) \
G_STMT_START { \
(array)->size = (array)->len = 0; \
g_free ((array)->data); \
(array)->data = NULL; \
} G_STMT_END
/**
* Creates a new AtomsContext for the given flavor.
*/
......@@ -641,7 +609,7 @@ atom_stss_clear (AtomSTSS * stss)
atom_array_clear (&stss->entries);
}
static void
void
atom_stbl_init (AtomSTBL * stbl)
{
atom_header_set (&stbl->header, FOURCC_stbl, 0, 0);
......@@ -656,7 +624,7 @@ atom_stbl_init (AtomSTBL * stbl)
atom_co64_init (&stbl->stco64);
}
static void
void
atom_stbl_clear (AtomSTBL * stbl)
{
atom_clear (&stbl->header);
......@@ -1370,7 +1338,7 @@ atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1545,7 +1513,7 @@ atom_url_copy_data (AtomURL * url, guint8 ** buffer, guint64 * size,
return original_offset - *offset;
}
static guint64
guint64
atom_stts_copy_data (AtomSTTS * stts, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1729,7 +1697,7 @@ sample_entry_mp4v_copy_data (SampleTableEntryMP4V * mp4v, guint8 ** buffer,
return *offset - original_offset;
}
static guint64
guint64
atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1757,7 +1725,7 @@ atom_stsz_copy_data (AtomSTSZ * stsz, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1785,7 +1753,7 @@ atom_stsc_copy_data (AtomSTSC * stsc, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1811,7 +1779,7 @@ atom_ctts_copy_data (AtomCTTS * ctts, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -1843,7 +1811,7 @@ atom_stco64_copy_data (AtomSTCO64 * stco64, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_stss_copy_data (AtomSTSS * stss, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -2152,7 +2120,7 @@ atom_edts_copy_data (AtomEDTS * edts, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
guint64
atom_trak_copy_data (AtomTRAK * trak, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
......@@ -2439,12 +2407,10 @@ atom_stbl_add_ctts_entry (AtomSTBL * stbl, guint32 nsamples, guint32 offset)
}
void
atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples, guint32 delta,
guint32 size, guint64 chunk_offset, gboolean sync,
gboolean do_pts, gint64 pts_offset)
{
AtomSTBL *stbl = &trak->mdia.minf.stbl;
atom_stts_add_entry (&stbl->stts, nsamples, delta);
atom_stsz_add_entry (&stbl->stsz, nsamples, size);
atom_stco64_add_entry (&stbl->stco64, chunk_offset);
......@@ -2456,6 +2422,16 @@ atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
atom_stbl_add_ctts_entry (stbl, nsamples, pts_offset);
}
void
atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint32 delta,
guint32 size, guint64 chunk_offset, gboolean sync,
gboolean do_pts, gint64 pts_offset)
{
AtomSTBL *stbl = &trak->mdia.minf.stbl;
atom_stbl_add_samples (stbl, nsamples, delta, size, chunk_offset, sync,
do_pts, pts_offset);
}
/* trak and moov molding */
guint32
......@@ -2576,7 +2552,7 @@ atom_moov_set_64bits (AtomMOOV * moov, gboolean large_file)
}
}
static void
void
atom_stco64_chunks_add_offset (AtomSTCO64 * stco64, guint32 offset)
{
guint i;
......
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
......@@ -59,6 +59,38 @@ struct { \
struct_type *data; \
}
/* storage helpers */
#define atom_array_init(array, reserve) \
G_STMT_START { \
(array)->len = 0; \
(array)->size = reserve; \
(array)->data = g_malloc (sizeof (*(array)->data) * reserve); \
} G_STMT_END
#define atom_array_append(array, elmt, inc) \
G_STMT_START { \
g_assert ((array)->data); \
g_assert (inc > 0); \
if (G_UNLIKELY ((array)->len == (array)->size)) { \
(array)->size += inc; \
(array)->data = \
g_realloc ((array)->data, sizeof (*((array)->data)) * (array)->size); \
} \
(array)->data[(array)->len] = elmt; \
(array)->len++; \
} G_STMT_END
#define atom_array_get_len(array) ((array)->len)
#define atom_array_index(array, index) ((array)->data[index])
#define atom_array_clear(array) \
G_STMT_START { \
(array)->size = (array)->len = 0; \
g_free ((array)->data); \
(array)->data = NULL; \
} G_STMT_END
/* light-weight context that may influence header atom tree construction */
typedef enum _AtomsTreeFlavor
{
......@@ -612,6 +644,10 @@ void atom_trak_add_samples (AtomTRAK * trak, guint32 nsamples, guint
void atom_trak_add_elst_entry (AtomTRAK * trak, guint32 duration,
guint32 media_time, guint32 rate);
guint32 atom_trak_get_timescale (AtomTRAK *trak);
void atom_stbl_add_samples (AtomSTBL * stbl, guint32 nsamples,
guint32 delta, guint32 size,
guint64 chunk_offset, gboolean sync,
gboolean do_pts, gint64 pts_offset);
AtomMOOV* atom_moov_new (AtomsContext *context);
void atom_moov_free (AtomMOOV *moov);
......@@ -622,6 +658,26 @@ void atom_moov_set_64bits (AtomMOOV *moov, gboolean large_file);
void atom_moov_chunks_add_offset (AtomMOOV *moov, guint32 offset);
void atom_moov_add_trak (AtomMOOV *moov, AtomTRAK *trak);
guint64 atom_mvhd_copy_data (AtomMVHD * atom, guint8 ** buffer,
guint64 * size, guint64 * offset);
void atom_stco64_chunks_add_offset (AtomSTCO64 * stco64, guint32 offset);
guint64 atom_trak_copy_data (AtomTRAK * atom, guint8 ** buffer,
guint64 * size, guint64 * offset);
void atom_stbl_clear (AtomSTBL * stbl);
void atom_stbl_init (AtomSTBL * stbl);
guint64 atom_stss_copy_data (AtomSTSS *atom, guint8 **buffer,
guint64 *size, guint64* offset);
guint64 atom_stts_copy_data (AtomSTTS *atom, guint8 **buffer,
guint64 *size, guint64* offset);
guint64 atom_stsc_copy_data (AtomSTSC *atom, guint8 **buffer,
guint64 *size, guint64* offset);
guint64 atom_stsz_copy_data (AtomSTSZ *atom, guint8 **buffer,
guint64 *size, guint64* offset);
guint64 atom_ctts_copy_data (AtomCTTS *atom, guint8 **buffer,
guint64 *size, guint64* offset);
guint64 atom_stco64_copy_data (AtomSTCO64 *atom, guint8 **buffer,
guint64 *size, guint64* offset);
/* media sample description related helpers */
typedef struct
......
This diff is collapsed.
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Unless otherwise indicated, Source Code is licensed under MIT license.
* See further explanation attached in License Statement (distributed in the file
* LICENSE).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __ATOMS_RECOVERY_H__
#define __ATOMS_RECOVERY_H__
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <gst/gst.h>
#include "atoms.h"
/* Version to be incremented each time we decide
* to change the file layout */
#define ATOMS_RECOV_FILE_VERSION 1
#define ATOMS_RECOV_QUARK (g_quark_from_string ("qtmux-atoms-recovery"))
/* gerror error codes */
#define ATOMS_RECOV_ERR_GENERIC 1
#define ATOMS_RECOV_ERR_FILE 2
#define ATOMS_RECOV_ERR_PARSING 3
#define ATOMS_RECOV_ERR_VERSION 4
/* this struct represents each buffer in a moov file, containing the info
* that is placed in the stsd children atoms
* Fields should be writen in BE order, and booleans should be writen as
* 1byte with 0 for false, anything otherwise */
#define TRAK_BUFFER_ENTRY_INFO_SIZE 34
typedef struct
{
guint32 track_id;
guint32 nsamples;
guint32 delta;
guint32 size;
guint64 chunk_offset;
guint64 pts_offset;
gboolean sync;
gboolean do_pts;
} TrakBufferEntryInfo;
typedef struct
{
guint32 trak_id;
guint32 duration; /* duration in trak timescale */
guint32 timescale; /* trak's timescale */
guint64 file_offset;
/* need for later updating duration */
guint64 tkhd_file_offset;
guint64 mdhd_file_offset;
/* need these offsets to update size */
guint32 trak_size;
guint64 mdia_file_offset;
guint32 mdia_size;
guint64 minf_file_offset;
guint32 minf_size;
guint64 stbl_file_offset;
guint32 stbl_size;
guint64 post_stsd_offset;
guint32 stsd_size;
/* for storing the samples info */
AtomSTBL stbl;
} TrakRecovData;
typedef struct
{
FILE * file;
gboolean rawfile;
/* results from parsing the input file */
guint64 data_size;
guint32 mdat_header_size;
guint mdat_start;
guint64 mdat_size;
} MdatRecovFile;
typedef struct
{
FILE * file;
guint32 timescale;
guint32 mvhd_pos;
guint32 mvhd_size;
guint32 prefix_size; /* prefix + ftyp total size */
gint num_traks;
TrakRecovData *traks_rd;
} MoovRecovFile;
gboolean atoms_recov_write_trak_info (FILE * f, AtomTRAK * trak);
gboolean atoms_recov_write_headers (FILE * f, AtomFTYP * ftyp,
GstBuffer * prefix, AtomMOOV * moov,
guint32 timescale,
guint32 traks_number);
gboolean atoms_recov_write_trak_samples (FILE * f, AtomTRAK * trak,
guint32 nsamples, guint32 delta,
guint32 size, guint64 chunk_offset,
gboolean sync, gboolean do_pts,
gint64 pts_offset);
MdatRecovFile * mdat_recov_file_create (FILE * file, gboolean datafile,
GError ** err);
void mdat_recov_file_free (MdatRecovFile * mrf);
MoovRecovFile * moov_recov_file_create (FILE * file, GError ** err);
void moov_recov_file_free (MoovRecovFile * moovrf);
gboolean moov_recov_parse_buffers (MoovRecovFile * moovrf,
MdatRecovFile * mdatrf,
GError ** err);
gboolean moov_recov_write_file (MoovRecovFile * moovrf,
MdatRecovFile * mdatrf, FILE * outf,
GError ** err);
#endif /* __ATOMS_RECOVERY_H__ */
......@@ -77,6 +77,7 @@ G_BEGIN_DECLS
#define FOURCC_vmhd GST_MAKE_FOURCC('v','m','h','d')
#define FOURCC_smhd GST_MAKE_FOURCC('s','m','h','d')
#define FOURCC_gmhd GST_MAKE_FOURCC('g','m','h','d')
#define FOURCC_hmhd GST_MAKE_FOURCC('h','m','h','d')
#define FOURCC_gmin GST_MAKE_FOURCC('g','m','i','n')
#define FOURCC_dinf GST_MAKE_FOURCC('d','i','n','f')
#define FOURCC_dref GST_MAKE_FOURCC('d','r','e','f')
......
This diff is collapsed.
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Unless otherwise indicated, Source Code is licensed under MIT license.
* See further explanation attached in License Statement (distributed in the file
* LICENSE).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __GST_QT_MOOV_RECOVER_H__
#define __GST_QT_MOOV_RECOVER_H__
#include <gst/gst.h>
#include "atoms.h"
#include "atomsrecovery.h"
G_BEGIN_DECLS
#define GST_TYPE_QT_MOOV_RECOVER (gst_qt_moov_recover_get_type())
#define GST_QT_MOOV_RECOVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QT_MOOV_RECOVER, GstQTMoovRecover))
#define GST_QT_MOOV_RECOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QT_MOOV_RECOVER, GstQTMoovRecover))
#define GST_IS_QT_MOOV_RECOVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QT_MOOV_RECOVER))
#define GST_IS_QT_MOOV_RECOVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QT_MOOV_RECOVER))
#define GST_QT_MOOV_RECOVER_CAST(obj) ((GstQTMoovRecover*)(obj))
typedef struct _GstQTMoovRecover GstQTMoovRecover;
typedef struct _GstQTMoovRecoverClass GstQTMoovRecoverClass;
struct _GstQTMoovRecover
{
GstPipeline pipeline;
GstTask *task;
GStaticRecMutex *task_mutex;
/* properties */
gboolean faststart_mode;
gchar *recovery_input;
gchar *fixed_output;
gchar *broken_input;
};
struct _GstQTMoovRecoverClass
{
GstPipelineClass parent_class;
};
GType gst_qt_moov_recover_get_type (void);
gboolean gst_qt_moov_recover_register (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_QT_MOOV_RECOVER_H__ */
/* Quicktime muxer plugin for GStreamer
* Copyright (C) 2008 Thiago Sousa Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008-2010 Thiago Santos <thiagoss@embedded.ufcg.edu.br>
* Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sf.net>
*
* This library is free software; you can redistribute it and/or
......@@ -108,7 +108,8 @@ enum
PROP_DO_CTTS,
PROP_FLAVOR,
PROP_FAST_START,
PROP_FAST_START_TEMP_FILE
PROP_FAST_START_TEMP_FILE,
PROP_MOOV_RECOV_FILE
};
/* some spare for header size as well */
......@@ -120,6 +121,7 @@ enum
#define DEFAULT_DO_CTTS FALSE
#define DEFAULT_FAST_START FALSE
#define DEFAULT_FAST_START_TEMP_FILE NULL
#define DEFAULT_MOOV_RECOV_FILE NULL
static void gst_qt_mux_finalize (GObject * object);
......@@ -234,11 +236,19 @@ gst_qt_mux_class_init (GstQTMuxClass * klass)
"when creating a faststart file. If null a filepath will be "
"created automatically", DEFAULT_FAST_START_TEMP_FILE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class, PROP_MOOV_RECOV_FILE,
g_param_spec_string ("moov-recovery-file", "File to store data for "
"posterior moov atom recovery", "File to be used to store "
"data for moov atom making movie file recovery possible in case "
"of a crash during muxing. Null for disabled. (Experimental)",
DEFAULT_MOOV_RECOV_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_qt_mux_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qt_mux_change_state);
gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_qt_mux_release_pad);
GST_DEBUG_CATEGORY_INIT (gst_qt_mux_debug, "qtmux", 0, "QT Muxer");
}
static void
......@@ -288,6 +298,10 @@ gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc)
fclose (qtmux->fast_start_file);
qtmux->fast_start_file = NULL;
}
if (qtmux->moov_recov_file) {
fclose (qtmux->moov_recov_file);
qtmux->moov_recov_file = NULL;
}
gst_tag_setter_reset_tags (GST_TAG_SETTER (qtmux));
/* reset pad data */
......@@ -350,6 +364,7 @@ gst_qt_mux_finalize (GObject * object)
gst_qt_mux_reset (qtmux, FALSE);
g_free (qtmux->fast_start_file_path);
g_free (qtmux->moov_recov_file_path);
atoms_context_free (qtmux->context);
gst_object_unref (qtmux->collect);
......@@ -1116,7 +1131,7 @@ gst_qt_mux_send_mdat_header (GstQTMux * qtmux, guint64 * off, guint64 size,
serialize_error:
{
GST_ELEMENT_ERROR (qtmux, STREAM, MUX, (NULL),
("Failed to serialize ftyp"));
("Failed to serialize mdat"));
return GST_FLOW_ERROR;
}
}
......@@ -1188,26 +1203,48 @@ serialize_error:
}
}
static GstFlowReturn
gst_qt_mux_prepare_and_send_ftyp (GstQTMux * qtmux)
static void
gst_qt_mux_prepare_ftyp (GstQTMux * qtmux, AtomFTYP ** p_ftyp,
GstBuffer ** p_prefix)
{
GstFlowReturn ret = GST_FLOW_OK;
GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
guint32 major, version;
GList *comp;
GstBuffer *prefix;
GstBuffer *prefix = NULL;
AtomFTYP *ftyp = NULL;
GST_DEBUG_OBJECT (qtmux, "Preparing to send ftyp atom");
GST_DEBUG_OBJECT (qtmux, "Preparing ftyp and possible prefix 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->longest_chunk,
qtmux->fast_start_file != NULL);
qtmux->ftyp = atom_ftyp_new (qtmux->context, major, version, comp);
ftyp = atom_ftyp_new (qtmux->context, major, version, comp);
if (comp)
g_list_free (comp);
if (prefix) {
if (p_prefix)
*p_prefix = prefix;
else
gst_buffer_unref (prefix);
}
*p_ftyp = ftyp;
}
static GstFlowReturn
gst_qt_mux_prepare_and_send_ftyp (GstQTMux * qtmux)
{
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *prefix = NULL;
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);
qtmux->ftyp = NULL;
}
gst_qt_mux_prepare_ftyp (qtmux, &qtmux->ftyp, &prefix);
if (prefix) {
ret = gst_qt_mux_send_buffer (qtmux, prefix, &qtmux->header_size, FALSE);
if (ret != GST_FLOW_OK)
......@@ -1227,6 +1264,57 @@ gst_qt_mux_start_file (GstQTMux * qtmux)
gst_pad_push_event (qtmux->srcpad,
gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
/* initialize our moov recovery file */
GST_OBJECT_LOCK (qtmux);
if (qtmux->moov_recov_file_path) {
GST_DEBUG_OBJECT (qtmux, "Openning moov recovery file: %s",
qtmux->moov_recov_file_path);
qtmux->moov_recov_file = g_fopen (qtmux->moov_recov_file_path, "wb+");
if (qtmux->moov_recov_file == NULL) {
GST_WARNING_OBJECT (qtmux, "Failed to open moov recovery file in %s",
qtmux->moov_recov_file_path);
} else {
GSList *walk;
gboolean fail = FALSE;
AtomFTYP *ftyp = NULL;
GstBuffer *prefix = NULL;
gst_qt_mux_prepare_ftyp (qtmux, &ftyp, &prefix);
if (!atoms_recov_write_headers (qtmux->moov_recov_file, ftyp, prefix,
qtmux->moov, qtmux->timescale,
g_slist_length (qtmux->collect->data))) {
GST_WARNING_OBJECT (qtmux, "Failed to write moov recovery file "
"headers");
fail = TRUE;
}
atom_ftyp_free (ftyp);
if (prefix)
gst_buffer_unref (prefix);
for (walk = qtmux->collect->data; walk && !fail;
walk = g_slist_next (walk)) {
GstCollectData *cdata = (GstCollectData *) walk->data;
GstQTPad *qpad = (GstQTPad *) cdata;
/* write info for each stream */
fail = atoms_recov_write_trak_info (qtmux->moov_recov_file, qpad->trak);
if (fail) {
GST_WARNING_OBJECT (qtmux, "Failed to write trak info to recovery "
"file");
}
}
if (fail) {
/* cleanup */
fclose (qtmux->moov_recov_file);
qtmux->moov_recov_file = NULL;
GST_WARNING_OBJECT (qtmux, "An error was detected while writing to "
"recover file, moov recovery won't work");
}
}
}
GST_OBJECT_UNLOCK (qtmux);
/*
* 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
......@@ -1606,6 +1694,16 @@ gst_qt_mux_add_buffer (GstQTMux * qtmux, GstQTPad * pad, GstBuffer * buf)
/* now we go and register this buffer/sample all over */
/* note that a new chunk is started each time (not fancy but works) */
if (qtmux->moov_recov_file) {
if (!atoms_recov_write_trak_samples (qtmux->moov_recov_file, pad->trak,
nsamples, scaled_duration, sample_size, chunk_offset, sync, do_pts,
pts_offset)) {
GST_WARNING_OBJECT (qtmux, "Failed to write sample information to "
"recovery file, disabling recovery");
fclose (qtmux->moov_recov_file);
qtmux->moov_recov_file = NULL;
}
}
atom_trak_add_samples (pad->trak, nsamples, scaled_duration, sample_size,
chunk_offset, sync, do_pts, pts_offset);
......@@ -2451,6 +2549,9 @@ gst_qt_mux_get_property (GObject * object,
case PROP_FAST_START_TEMP_FILE:
g_value_set_string (value, qtmux->fast_start_file_path);
break;
case PROP_MOOV_RECOV_FILE:
g_value_set_string (value, qtmux->moov_recov_file_path);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -2499,6 +2600,10 @@ gst_qt_mux_set_property (GObject * object,
gst_qt_mux_generate_fast_start_file_path (qtmux);
}
break;
case PROP_MOOV_RECOV_FILE:
g_free (qtmux->moov_recov_file_path);
qtmux->moov_recov_file_path = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -2545,7 +2650,6 @@ gst_qt_mux_change_state (GstElement * element, GstStateChange transition)
return ret;
}
gboolean
gst_qt_mux_register (GstPlugin * plugin)
{
......@@ -2613,18 +2717,3 @@ gst_qt_mux_register (GstPlugin * plugin)
return TRUE;
}
gboolean
gst_qt_mux_plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_qt_mux_debug, "qtmux", 0,