From: Thiago Santos Date: Wed, 15 Sep 2010 20:54:49 +0000 (-0300) Subject: qtmux: Follow xmp serialization guidelines closer X-Git-Tag: 1.19.3~507^2~16490 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=804734689839bb0645a6bbf9fafdbb16ae31e15c;p=platform%2Fupstream%2Fgstreamer.git 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. --- diff --git a/gst/qtmux/atoms.c b/gst/qtmux/atoms.c index 94a1a45..29d1017 100644 --- a/gst/qtmux/atoms.c +++ b/gst/qtmux/atoms.c @@ -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); - - atom_moov_init_metatags (moov, &moov->context); + 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"); + } - 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); +} diff --git a/gst/qtmux/atoms.h b/gst/qtmux/atoms.h index bdf83be..387904b 100644 --- a/gst/qtmux/atoms.h +++ b/gst/qtmux/atoms.h @@ -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); /* diff --git a/gst/qtmux/fourcc.h b/gst/qtmux/fourcc.h index 51a2a5f..cbef8bb 100644 --- a/gst/qtmux/fourcc.h +++ b/gst/qtmux/fourcc.h @@ -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 */ diff --git a/gst/qtmux/gstqtmux.c b/gst/qtmux/gstqtmux.c index a599f58..7f5ab30 100644 --- a/gst/qtmux/gstqtmux.c +++ b/gst/qtmux/gstqtmux.c @@ -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; } diff --git a/gst/qtmux/gstqtmux.h b/gst/qtmux/gstqtmux.h index 16e7f42..013211a 100644 --- a/gst/qtmux/gstqtmux.h +++ b/gst/qtmux/gstqtmux.h @@ -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;