qtmux: Follow xmp serialization guidelines closer

qt and isom variants have different ways of serializing
xmp, follow these guidelines.

Those can be found in Adobe's xmp docs.
This commit is contained in:
Thiago Santos 2010-09-15 17:54:49 -03:00 committed by Tim-Philipp Müller
parent 365b419216
commit 7065a65ec8
5 changed files with 146 additions and 16 deletions

View file

@ -206,6 +206,23 @@ atom_data_free (AtomData * data)
g_free (data);
}
static AtomUUID *
atom_uuid_new (void)
{
AtomUUID *uuid = g_new0 (AtomUUID, 1);
atom_header_set (&uuid->header, FOURCC_uuid, 0, 0);
return uuid;
}
static void
atom_uuid_free (AtomUUID * data)
{
atom_clear (&data->header);
g_free (data->data);
g_free (data);
}
static void
atom_ftyp_init (AtomFTYP * ftyp, guint32 major, guint32 version, GList * brands)
{
@ -1319,6 +1336,23 @@ atom_data_copy_data (AtomData * data, guint8 ** buffer, guint64 * size,
return *offset - original_offset;
}
static guint64
atom_uuid_copy_data (AtomUUID * uuid, guint8 ** buffer, guint64 * size,
guint64 * offset)
{
guint64 original_offset = *offset;
if (!atom_copy_data (&uuid->header, buffer, size, offset)) {
return 0;
}
prop_copy_uint8_array (uuid->uuid, 16, buffer, size, offset);
if (uuid->datalen)
prop_copy_uint8_array (uuid->data, uuid->datalen, buffer, size, offset);
atom_write_size (buffer, size, offset, original_offset);
return *offset - original_offset;
}
guint64
atom_ftyp_copy_data (AtomFTYP * ftyp, guint8 ** buffer, guint64 * size,
guint64 * offset)
@ -2775,17 +2809,23 @@ atom_moov_add_3gp_uint_tag (AtomMOOV * moov, guint32 fourcc, guint16 value)
void
atom_moov_add_xmp_tags (AtomMOOV * moov, const GstTagList * tags)
{
GstBuffer *xmpbuffer = gst_tag_list_to_xmp_buffer (tags, TRUE);
GstBuffer *xmpbuffer;
AtomData *data_atom = NULL;
data_atom = atom_data_new_from_gst_buffer (FOURCC_XMP_, xmpbuffer);
gst_buffer_unref (xmpbuffer);
if (moov->context.flavor == ATOMS_TREE_FLAVOR_MOV) {
xmpbuffer = gst_tag_list_to_xmp_buffer (tags, TRUE);
if (xmpbuffer) {
data_atom = atom_data_new_from_gst_buffer (FOURCC_XMP_, xmpbuffer);
atom_moov_init_metatags (moov, &moov->context);
moov->udta->entries = g_list_append (moov->udta->entries,
build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
atom_data_free));
gst_buffer_unref (xmpbuffer);
}
} else {
GST_DEBUG ("Not adding xmp to moov atom, it is only used in 'mov' format");
}
atom_moov_init_metatags (moov, &moov->context);
moov->udta->entries = g_list_append (moov->udta->entries,
build_atom_info_wrapper ((Atom *) data_atom, atom_data_copy_data,
atom_data_free));
}
/*
@ -3566,3 +3606,30 @@ build_ima_adpcm_extension (gint channels, gint rate, gint blocksize)
return build_atom_info_wrapper ((Atom *) wave, atom_wave_copy_data,
atom_wave_free);
}
AtomInfo *
build_uuid_xmp_atom (const GstTagList * taglist)
{
GstBuffer *xmp_data;
AtomUUID *uuid;
static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
0x97, 0xA9, 0x42, 0xE8,
0x9C, 0x71, 0x99, 0x94,
0x91, 0xE3, 0xAF, 0xAC
};
xmp_data = gst_tag_list_to_xmp_buffer (taglist, TRUE);
if (xmp_data == NULL)
return NULL;
uuid = atom_uuid_new ();
memcpy (uuid->uuid, xmp_uuid, 16);
uuid->data = g_malloc (GST_BUFFER_SIZE (xmp_data));
uuid->datalen = GST_BUFFER_SIZE (xmp_data);
memcpy (uuid->data, GST_BUFFER_DATA (xmp_data), GST_BUFFER_SIZE (xmp_data));
gst_buffer_unref (xmp_data);
return build_atom_info_wrapper ((Atom *) uuid, atom_uuid_copy_data,
atom_uuid_free);
}

View file

@ -147,9 +147,22 @@ typedef struct _AtomData
/* not written */
guint32 datalen;
guint8 *data;
} AtomData;
typedef struct _AtomUUID
{
Atom header;
guint8 uuid[16];
/* not written */
guint32 datalen;
guint8 *data;
} AtomUUID;
typedef struct _AtomFTYP
{
Atom header;
@ -741,6 +754,7 @@ AtomInfo * build_gama_atom (gdouble gamma);
AtomInfo * build_SMI_atom (const GstBuffer *seqh);
AtomInfo * build_ima_adpcm_extension (gint channels, gint rate,
gint blocksize);
AtomInfo * build_uuid_xmp_atom (const GstTagList * taglist);
/*

View file

@ -187,6 +187,7 @@ G_BEGIN_DECLS
#define FOURCC_soco GST_MAKE_FOURCC('s','o','c','o')
#define FOURCC_sosn GST_MAKE_FOURCC('s','o','s','n')
#define FOURCC_XMP_ GST_MAKE_FOURCC('X','M','P','_')
#define FOURCC_uuid GST_MAKE_FOURCC('u','u','i','d')
/* SVQ3 fourcc */

View file

@ -300,6 +300,12 @@ gst_qt_mux_reset (GstQTMux * qtmux, gboolean alloc)
fclose (qtmux->moov_recov_file);
qtmux->moov_recov_file = NULL;
}
for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) {
AtomInfo *ainfo = (AtomInfo *) walk->data;
ainfo->free_func (ainfo->atom);
}
g_slist_free (qtmux->extra_atoms);
qtmux->extra_atoms = NULL;
GST_OBJECT_LOCK (qtmux);
gst_tag_setter_reset_tags (GST_TAG_SETTER (qtmux));
@ -880,15 +886,24 @@ gst_qt_mux_add_xmp_tags (GstQTMux * qtmux, const GstTagList * list)
{
GstQTMuxClass *qtmux_klass = (GstQTMuxClass *) (G_OBJECT_GET_CLASS (qtmux));
/* adobe specs only say 'quicktime', but I guess we can extrapolate to
* mp4 and gpp. Keep mj2 out for now as we don't add any tags for it yet.
/* adobe specs only have 'quicktime' and 'mp4',
* but I guess we can extrapolate to gpp.
* Keep mj2 out for now as we don't add any tags for it yet.
* If you have further info about xmp on these formats, please share */
if (qtmux_klass->format == GST_QT_MUX_FORMAT_MJ2)
return;
GST_DEBUG_OBJECT (qtmux, "Adding xmp tags");
atom_moov_add_xmp_tags (qtmux->moov, list);
if (qtmux_klass->format == GST_QT_MUX_FORMAT_QT) {
atom_moov_add_xmp_tags (qtmux->moov, list);
} else {
/* for isom/mp4, it is a top level uuid atom */
AtomInfo *ainfo = build_uuid_xmp_atom (list);
if (ainfo) {
qtmux->extra_atoms = g_slist_prepend (qtmux->extra_atoms, ainfo);
}
}
}
static void
@ -1489,6 +1504,17 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
GST_DEBUG_OBJECT (qtmux, "calculated moov atom size %" G_GUINT64_FORMAT,
offset);
offset += qtmux->header_size + (large_file ? 16 : 8);
/* sum up with the extra atoms size */
for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) {
guint64 extra_size = 0, extra_offset = 0;
AtomInfo *ainfo = (AtomInfo *) walk->data;
if (!ainfo->copy_data_func (ainfo->atom, NULL, &extra_size,
&extra_offset))
goto serialize_error;
offset += extra_offset;
}
} else
offset = qtmux->header_size;
atom_moov_chunks_add_offset (qtmux->moov, offset);
@ -1497,8 +1523,7 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
offset = size = 0;
data = NULL;
GST_LOG_OBJECT (qtmux, "Copying movie header into buffer");
ret = atom_moov_copy_data (qtmux->moov, &data, &size, &offset);
if (!ret)
if (!atom_moov_copy_data (qtmux->moov, &data, &size, &offset))
goto serialize_error;
buffer = gst_buffer_new ();
@ -1509,6 +1534,23 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
GST_DEBUG_OBJECT (qtmux, "Pushing movie atoms");
gst_qt_mux_send_buffer (qtmux, buffer, NULL, FALSE);
/* push extra top-level atoms */
for (walk = qtmux->extra_atoms; walk; walk = g_slist_next (walk)) {
AtomInfo *ainfo = (AtomInfo *) walk->data;
offset = size = 0;
data = NULL;
if (!ainfo->copy_data_func (ainfo->atom, &data, &size, &offset))
goto serialize_error;
buffer = gst_buffer_new ();
GST_BUFFER_MALLOCDATA (buffer) = GST_BUFFER_DATA (buffer) = data;
GST_BUFFER_SIZE (buffer) = offset;
GST_DEBUG_OBJECT (qtmux, "Pushing extra top-level atom %" GST_FOURCC_FORMAT,
GST_FOURCC_ARGS (ainfo->atom->type));
gst_qt_mux_send_buffer (qtmux, buffer, NULL, FALSE);
}
/* if needed, send mdat atom and move buffered data into it */
if (qtmux->fast_start_file) {
/* mdat size = accumulated (buffered data) + mdat atom header */
@ -1520,12 +1562,12 @@ gst_qt_mux_stop_file (GstQTMux * qtmux)
if (ret != GST_FLOW_OK)
return ret;
} else {
/* mdata needs update iff not using faststart */
GST_DEBUG_OBJECT (qtmux, "updating mdata size");
/* mdat needs update iff not using faststart */
GST_DEBUG_OBJECT (qtmux, "updating mdat size");
ret = gst_qt_mux_update_mdat_size (qtmux, qtmux->mdat_pos,
qtmux->mdat_size, NULL);
/* note; no seeking back to the end of file is done,
* since we longer write anything anyway */
* since we no longer write anything anyway */
}
return ret;
@ -1874,8 +1916,12 @@ gst_qt_mux_collected (GstCollectPads * pads, gpointer user_data)
} else {
ret = gst_qt_mux_stop_file (qtmux);
if (ret == GST_FLOW_OK) {
GST_DEBUG_OBJECT (qtmux, "Pushing eos");
gst_pad_push_event (qtmux->srcpad, gst_event_new_eos ());
ret = GST_FLOW_UNEXPECTED;
} else {
GST_WARNING_OBJECT (qtmux, "Failed to stop file: %s",
gst_flow_get_name (ret));
}
qtmux->state = GST_QT_MUX_STATE_EOS;
}

View file

@ -144,6 +144,8 @@ struct _GstQTMux
AtomsContext *context;
AtomFTYP *ftyp;
AtomMOOV *moov;
GSList *extra_atoms; /* list of extra top-level atoms (e.g. UUID for xmp)
* Stored as AtomInfo structs */
/* fast start */
FILE *fast_start_file;