mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 00:01:23 +00:00
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
This commit is contained in:
parent
b9f8f5d281
commit
e1c1405396
11 changed files with 2005 additions and 79 deletions
|
@ -4,7 +4,10 @@ plugin_LTLIBRARIES = libgstqtmux.la
|
|||
|
||||
# sources used to compile this plug-in
|
||||
libgstqtmux_la_SOURCES = gstqtmux.c \
|
||||
gstqtmoovrecover.c \
|
||||
gstqtmuxplugin.c \
|
||||
atoms.c \
|
||||
atomsrecovery.c \
|
||||
descriptors.c \
|
||||
properties.c \
|
||||
gstqtmuxmap.c
|
||||
|
@ -18,9 +21,12 @@ libgstqtmux_la_LIBTOOLFLAGS = --tag=disable-static
|
|||
|
||||
# headers we need but don't want installed
|
||||
noinst_HEADERS = gstqtmux.h \
|
||||
gstqtmoovrecover.h \
|
||||
atoms.h \
|
||||
atomsrecovery.h \
|
||||
descriptors.h \
|
||||
properties.h \
|
||||
fourcc.h \
|
||||
ftypcc.h \
|
||||
gstqtmuxmap.h
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
|
|
1087
gst/qtmux/atomsrecovery.c
Normal file
1087
gst/qtmux/atomsrecovery.c
Normal file
File diff suppressed because it is too large
Load diff
159
gst/qtmux/atomsrecovery.h
Normal file
159
gst/qtmux/atomsrecovery.h
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* 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')
|
||||
|
|
391
gst/qtmux/gstqtmoovrecover.c
Normal file
391
gst/qtmux/gstqtmoovrecover.c
Normal file
|
@ -0,0 +1,391 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:gstqtmoovrecover
|
||||
* @short_description: Utility element for recovering unfinished quicktime files
|
||||
*
|
||||
* <refsect2>
|
||||
* <para>
|
||||
* This element recovers quicktime files created with qtmux using the moov recovery feature.
|
||||
* </para>
|
||||
* <title>Example pipelines</title>
|
||||
* <para>
|
||||
* <programlisting>
|
||||
* TODO
|
||||
* </programlisting>
|
||||
* </refsect2>
|
||||
*
|
||||
* Last reviewed on 2010-02-01
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstqtmoovrecover.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_qt_moov_recover_debug);
|
||||
#define GST_CAT_DEFAULT gst_qt_moov_recover_debug
|
||||
|
||||
static GstElementDetails gst_qt_moov_recover_details =
|
||||
GST_ELEMENT_DETAILS ("QT Moov Recover",
|
||||
"Util", "Recovers unfinished qtmux files",
|
||||
"Thiago Santos <thiago.sousa.santos@collabora.co.uk>");
|
||||
|
||||
/* QTMoovRecover signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_RECOVERY_INPUT,
|
||||
PROP_BROKEN_INPUT,
|
||||
PROP_FIXED_OUTPUT,
|
||||
PROP_FAST_START_MODE
|
||||
};
|
||||
|
||||
GST_BOILERPLATE (GstQTMoovRecover, gst_qt_moov_recover, GstPipeline,
|
||||
GST_TYPE_PIPELINE);
|
||||
|
||||
/* property functions */
|
||||
static void gst_qt_moov_recover_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec);
|
||||
static void gst_qt_moov_recover_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstStateChangeReturn gst_qt_moov_recover_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
|
||||
static void gst_qt_moov_recover_finalize (GObject * object);
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
#if 0
|
||||
GstQTMoovRecoverClass *klass = (GstQTMoovRecoverClass *) g_class;
|
||||
#endif
|
||||
gst_element_class_set_details (element_class, &gst_qt_moov_recover_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_class_init (GstQTMoovRecoverClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
gobject_class->finalize = gst_qt_moov_recover_finalize;
|
||||
gobject_class->get_property = gst_qt_moov_recover_get_property;
|
||||
gobject_class->set_property = gst_qt_moov_recover_set_property;
|
||||
|
||||
gstelement_class->change_state = gst_qt_moov_recover_change_state;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FIXED_OUTPUT,
|
||||
g_param_spec_string ("fixed-output",
|
||||
"Path to write the fixed file",
|
||||
"Path to write the fixed file to (used as output)",
|
||||
NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_class, PROP_BROKEN_INPUT,
|
||||
g_param_spec_string ("broken-input",
|
||||
"Path to broken input file",
|
||||
"Path to broken input file. (If qtmux was on faststart mode, this "
|
||||
"file is the faststart file)", NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_class, PROP_RECOVERY_INPUT,
|
||||
g_param_spec_string ("recovery-input",
|
||||
"Path to recovery file",
|
||||
"Path to recovery file (used as input)", NULL, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_class, PROP_FAST_START_MODE,
|
||||
g_param_spec_boolean ("faststart-mode",
|
||||
"If the broken input is from faststart mode",
|
||||
"If the broken input is from faststart mode",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_qt_moov_recover_debug, "qtmoovrecover", 0,
|
||||
"QT Moovie Recover");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_init (GstQTMoovRecover * qtmr,
|
||||
GstQTMoovRecoverClass * qtmr_klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_finalize (GObject * object)
|
||||
{
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_run (void *data)
|
||||
{
|
||||
FILE *moovrec = NULL;
|
||||
FILE *mdatinput = NULL;
|
||||
FILE *output = NULL;
|
||||
MdatRecovFile *mdat_recov = NULL;
|
||||
MoovRecovFile *moov_recov = NULL;
|
||||
GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (data);
|
||||
GError *err = NULL;
|
||||
|
||||
GST_LOG_OBJECT (qtmr, "Starting task");
|
||||
|
||||
GST_DEBUG_OBJECT (qtmr, "Validating properties");
|
||||
GST_OBJECT_LOCK (qtmr);
|
||||
/* validate properties */
|
||||
if (qtmr->broken_input == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
|
||||
("Please set broken-input property"), NULL);
|
||||
goto end;
|
||||
}
|
||||
if (qtmr->recovery_input == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
|
||||
("Please set recovery-input property"), NULL);
|
||||
goto end;
|
||||
}
|
||||
if (qtmr->fixed_output == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, SETTINGS,
|
||||
("Please set fixed-output property"), NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (qtmr, "Opening input/output files");
|
||||
/* open files */
|
||||
moovrec = g_fopen (qtmr->recovery_input, "rb");
|
||||
if (moovrec == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
|
||||
("Failed to open recovery-input file"), NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
mdatinput = g_fopen (qtmr->broken_input, "rb");
|
||||
if (mdatinput == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ,
|
||||
("Failed to open broken-input file"), NULL);
|
||||
goto end;
|
||||
}
|
||||
output = g_fopen (qtmr->fixed_output, "wb+");
|
||||
if (output == NULL) {
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, OPEN_READ_WRITE,
|
||||
("Failed to open fixed-output file"), NULL);
|
||||
goto end;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
|
||||
GST_DEBUG_OBJECT (qtmr, "Parsing input files");
|
||||
/* now create our structures */
|
||||
mdat_recov = mdat_recov_file_create (mdatinput, qtmr->faststart_mode, &err);
|
||||
mdatinput = NULL;
|
||||
if (mdat_recov == NULL) {
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
|
||||
("Broken file could not be parsed correctly"), NULL);
|
||||
goto end;
|
||||
}
|
||||
moov_recov = moov_recov_file_create (moovrec, &err);
|
||||
moovrec = NULL;
|
||||
if (moov_recov == NULL) {
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED,
|
||||
("Recovery file could not be parsed correctly"), NULL);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* now parse the buffers data from moovrec */
|
||||
if (!moov_recov_parse_buffers (moov_recov, mdat_recov, &err)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (qtmr, "Writing fixed file to output");
|
||||
if (!moov_recov_write_file (moov_recov, mdat_recov, output, &err)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* here means success */
|
||||
GST_DEBUG_OBJECT (qtmr, "Finished successfully, posting EOS");
|
||||
gst_element_post_message (GST_ELEMENT_CAST (qtmr),
|
||||
gst_message_new_eos (GST_OBJECT_CAST (qtmr)));
|
||||
|
||||
end:
|
||||
GST_LOG_OBJECT (qtmr, "Finalizing task");
|
||||
if (err) {
|
||||
GST_ELEMENT_ERROR (qtmr, RESOURCE, FAILED, (err->message), NULL);
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
if (moov_recov)
|
||||
moov_recov_file_free (moov_recov);
|
||||
if (moovrec)
|
||||
fclose (moovrec);
|
||||
|
||||
if (mdat_recov)
|
||||
mdat_recov_file_free (mdat_recov);
|
||||
if (mdatinput)
|
||||
fclose (mdatinput);
|
||||
|
||||
if (output)
|
||||
fclose (output);
|
||||
GST_LOG_OBJECT (qtmr, "Leaving task");
|
||||
gst_task_stop (qtmr->task);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_get_property (GObject * object,
|
||||
guint prop_id, GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
|
||||
|
||||
GST_OBJECT_LOCK (qtmr);
|
||||
switch (prop_id) {
|
||||
case PROP_FAST_START_MODE:
|
||||
g_value_set_boolean (value, qtmr->faststart_mode);
|
||||
break;
|
||||
case PROP_BROKEN_INPUT:
|
||||
g_value_set_string (value, qtmr->broken_input);
|
||||
break;
|
||||
case PROP_RECOVERY_INPUT:
|
||||
g_value_set_string (value, qtmr->recovery_input);
|
||||
break;
|
||||
case PROP_FIXED_OUTPUT:
|
||||
g_value_set_string (value, qtmr->fixed_output);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_qt_moov_recover_set_property (GObject * object,
|
||||
guint prop_id, const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (object);
|
||||
|
||||
GST_OBJECT_LOCK (qtmr);
|
||||
switch (prop_id) {
|
||||
case PROP_FAST_START_MODE:
|
||||
qtmr->faststart_mode = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_BROKEN_INPUT:
|
||||
g_free (qtmr->broken_input);
|
||||
qtmr->broken_input = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_RECOVERY_INPUT:
|
||||
g_free (qtmr->recovery_input);
|
||||
qtmr->recovery_input = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_FIXED_OUTPUT:
|
||||
g_free (qtmr->fixed_output);
|
||||
qtmr->fixed_output = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
GST_OBJECT_UNLOCK (qtmr);
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_qt_moov_recover_change_state (GstElement * element,
|
||||
GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstQTMoovRecover *qtmr = GST_QT_MOOV_RECOVER_CAST (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
qtmr->task = gst_task_create (gst_qt_moov_recover_run, qtmr);
|
||||
qtmr->task_mutex = g_new (GStaticRecMutex, 1);
|
||||
g_static_rec_mutex_init (qtmr->task_mutex);
|
||||
gst_task_set_lock (qtmr->task, qtmr->task_mutex);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
gst_task_start (qtmr->task);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
gst_task_stop (qtmr->task);
|
||||
gst_task_join (qtmr->task);
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
g_assert (gst_task_get_state (qtmr->task) == GST_TASK_STOPPED);
|
||||
gst_object_unref (qtmr->task);
|
||||
qtmr->task = NULL;
|
||||
g_static_rec_mutex_free (qtmr->task_mutex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gst_qt_moov_recover_register (GstPlugin * plugin)
|
||||
{
|
||||
return gst_element_register (plugin, "qtmoovrecover", GST_RANK_NONE,
|
||||
GST_TYPE_QT_MOOV_RECOVER);
|
||||
}
|
88
gst/qtmux/gstqtmoovrecover.h
Normal file
88
gst/qtmux/gstqtmoovrecover.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* 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__ */
|
|
@ -1,5 +1,5 @@
|
|||
/* 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 void
|
||||
gst_qt_mux_prepare_ftyp (GstQTMux * qtmux, AtomFTYP ** p_ftyp,
|
||||
GstBuffer ** p_prefix)
|
||||
{
|
||||
GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
|
||||
guint32 major, version;
|
||||
GList *comp;
|
||||
GstBuffer *prefix = NULL;
|
||||
AtomFTYP *ftyp = NULL;
|
||||
|
||||
GST_DEBUG_OBJECT (qtmux, "Preparing ftyp and possible prefix atom");
|
||||
|
||||
/* init and send context and ftyp based on current property state */
|
||||
gst_qt_mux_map_format_to_header (qtmux_klass->format, &prefix, &major,
|
||||
&version, &comp, qtmux->moov, qtmux->longest_chunk,
|
||||
qtmux->fast_start_file != NULL);
|
||||
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;
|
||||
GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
|
||||
guint32 major, version;
|
||||
GList *comp;
|
||||
GstBuffer *prefix;
|
||||
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)
|
||||
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);
|
||||
if (comp)
|
||||
g_list_free (comp);
|
||||
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, "QT Muxer");
|
||||
|
||||
return gst_qt_mux_register (plugin);
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"qtmux",
|
||||
"Quicktime Muxer plugin",
|
||||
gst_qt_mux_plugin_init, VERSION, "LGPL", "gsoc2008 package",
|
||||
"embedded.ufcg.edu.br")
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* 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
|
||||
|
@ -48,6 +48,7 @@
|
|||
|
||||
#include "fourcc.h"
|
||||
#include "atoms.h"
|
||||
#include "atomsrecovery.h"
|
||||
#include "gstqtmuxmap.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@ -144,6 +145,9 @@ struct _GstQTMux
|
|||
/* fast start */
|
||||
FILE *fast_start_file;
|
||||
|
||||
/* moov recovery */
|
||||
FILE *moov_recov_file;
|
||||
|
||||
/* properties */
|
||||
guint32 timescale;
|
||||
AtomsTreeFlavor flavor;
|
||||
|
@ -151,6 +155,7 @@ struct _GstQTMux
|
|||
gboolean large_file;
|
||||
gboolean guess_pts;
|
||||
gchar *fast_start_file_path;
|
||||
gchar *moov_recov_file_path;
|
||||
|
||||
/* for collect pads event handling function */
|
||||
GstPadEventFunction collect_event;
|
||||
|
@ -178,6 +183,7 @@ typedef struct _GstQTMuxClassParams
|
|||
#define GST_QT_MUX_PARAMS_QDATA g_quark_from_static_string("qt-mux-params")
|
||||
|
||||
GType gst_qt_mux_get_type (void);
|
||||
gboolean gst_qt_mux_register (GstPlugin * plugin);
|
||||
|
||||
/* FIXME: ideally classification tag should be added and
|
||||
* registered in gstreamer core gsttaglist
|
||||
|
|
67
gst/qtmux/gstqtmuxplugin.c
Normal file
67
gst/qtmux/gstqtmuxplugin.c
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* Quicktime muxer plugin for GStreamer
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstqtmux.h"
|
||||
#include "gstqtmoovrecover.h"
|
||||
|
||||
static gboolean
|
||||
gst_qt_mux_plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_qt_mux_register (plugin))
|
||||
return FALSE;
|
||||
if (!gst_qt_moov_recover_register (plugin))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"qtmux",
|
||||
"Quicktime Muxer plugin",
|
||||
gst_qt_mux_plugin_init, VERSION, "LGPL", "gsoc2008 package",
|
||||
"embedded.ufcg.edu.br")
|
Loading…
Reference in a new issue