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)
{
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)
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));
}
/*
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);
+}
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));
{
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
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);
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 ();
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 */
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;
} 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;
}