From 7772a25fdccd92f39a8409cbac5ebd0cc96712bf Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Mon, 2 Feb 2015 19:46:27 -0300 Subject: [PATCH] matroskamux: store and write stream tags Separate global from stream tags storage and write them to the appropriate tags entry in the output --- gst/matroska/matroska-ids.h | 1 + gst/matroska/matroska-mux.c | 98 ++++++++++++++++++++++++++++++++++++++++----- gst/matroska/matroska-mux.h | 10 ++++- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/gst/matroska/matroska-ids.h b/gst/matroska/matroska-ids.h index d971ba2..2aec1b4 100644 --- a/gst/matroska/matroska-ids.h +++ b/gst/matroska/matroska-ids.h @@ -507,6 +507,7 @@ struct _GstMatroskaTrackContext { gint index_writer_id; /* some often-used info */ + guint64 track_uid; gchar *codec_id, *codec_name, *name, *language; gpointer codec_priv; gsize codec_priv_size; diff --git a/gst/matroska/matroska-mux.c b/gst/matroska/matroska-mux.c index 9e0fc08..d1d9f12 100644 --- a/gst/matroska/matroska-mux.c +++ b/gst/matroska/matroska-mux.c @@ -246,6 +246,8 @@ static gboolean flac_streamheader_to_codecdata (const GValue * streamheader, static void gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, gpointer data); +static void gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux); +static gboolean gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux); /* Cannot use boilerplate macros here because we need the full init function * signature with the additional class argument, so we use the right template @@ -560,6 +562,10 @@ gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full) g_free (collect_pad->track->codec_priv); g_free (collect_pad->track); collect_pad->track = NULL; + if (collect_pad->tags) { + gst_tag_list_unref (collect_pad->tags); + collect_pad->tags = NULL; + } } if (!full && type != 0) { @@ -586,12 +592,15 @@ gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full) context->type = type; context->name = name; + context->track_uid = gst_matroska_mux_create_uid (collect_pad->mux); /* TODO: check default values for the context */ context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT; collect_pad->track = context; collect_pad->duration = 0; collect_pad->start_ts = GST_CLOCK_TIME_NONE; collect_pad->end_ts = GST_CLOCK_TIME_NONE; + collect_pad->tags = gst_tag_list_new_empty (); + gst_tag_list_set_scope (collect_pad->tags, GST_TAG_SCOPE_STREAM); } } @@ -806,8 +815,12 @@ gst_matroska_mux_handle_sink_event (GstCollectPads * pads, } /* FIXME: what about stream-specific tags? */ - gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list, - gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux))); + if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) { + gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list, + gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux))); + } else { + gst_tag_list_insert (collect_pad->tags, list, GST_TAG_MERGE_REPLACE); + } gst_event_unref (event); /* handled this, don't want collectpads to forward it downstream */ @@ -2281,6 +2294,7 @@ gst_matroska_mux_request_new_pad (GstElement * element, sizeof (GstMatroskamuxPad), (GstCollectDataDestroyNotify) gst_matroska_pad_free, locked); + collect_pad->mux = mux; collect_pad->track = context; gst_matroska_pad_reset (collect_pad, FALSE); collect_pad->track->codec_id = id; @@ -2371,8 +2385,7 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux, gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKNUMBER, context->num); gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type); - gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, - gst_matroska_mux_create_uid (mux)); + gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->track_uid); if (context->default_duration) { gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION, context->default_duration); @@ -2659,21 +2672,25 @@ gst_matroska_mux_start (GstMatroskaMux * mux) if (mux->streamable) { const GstTagList *tags; + gboolean has_main_tags; /* tags */ tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux)); + has_main_tags = tags != NULL && !gst_tag_list_is_empty (tags); - if (tags != NULL && !gst_tag_list_is_empty (tags)) { + if (has_main_tags || gst_matroska_mux_streams_have_tags (mux)) { guint64 master_tags, master_tag; GST_DEBUG_OBJECT (mux, "Writing tags"); - /* TODO: maybe limit via the TARGETS id by looking at the source pad */ mux->tags_pos = ebml->pos; master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS); - master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG); - gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml); - gst_ebml_write_master_finish (ebml, master_tag); + if (has_main_tags) { + master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG); + gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml); + gst_ebml_write_master_finish (ebml, master_tag); + } + gst_matroska_mux_write_streams_tags (mux); gst_ebml_write_master_finish (ebml, master_tags); } } @@ -2885,6 +2902,57 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag, } } +static void +gst_matroska_mux_write_stream_tags (GstMatroskaMux * mux, GstMatroskaPad * mpad) +{ + guint64 master_tag, master_targets; + GstEbmlWrite *ebml; + + ebml = mux->ebml_write; + + if (G_UNLIKELY (mpad->tags == NULL || gst_tag_list_is_empty (mpad->tags))) + return; + + master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG); + master_targets = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS); + + gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETTRACKUID, + mpad->track->track_uid); + + gst_ebml_write_master_finish (ebml, master_targets); + gst_tag_list_foreach (mpad->tags, gst_matroska_mux_write_simple_tag, ebml); + gst_ebml_write_master_finish (ebml, master_tag); +} + +static void +gst_matroska_mux_write_streams_tags (GstMatroskaMux * mux) +{ + GSList *walk; + + for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) { + GstMatroskaPad *collect_pad; + + collect_pad = (GstMatroskaPad *) walk->data; + + gst_matroska_mux_write_stream_tags (mux, collect_pad); + } +} + +static gboolean +gst_matroska_mux_streams_have_tags (GstMatroskaMux * mux) +{ + GSList *walk; + + for (walk = mux->collect->data; walk; walk = g_slist_next (walk)) { + GstMatroskaPad *collect_pad; + + collect_pad = (GstMatroskaPad *) walk->data; + if (!gst_tag_list_is_empty (collect_pad->tags)) + return TRUE; + } + return FALSE; +} + #if 0 static void gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux, @@ -2940,6 +3008,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) guint64 duration = 0; GSList *collected; const GstTagList *tags; + gboolean has_main_tags; /* finish last cluster */ if (mux->cluster) { @@ -2977,8 +3046,9 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) /* tags */ tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux)); + has_main_tags = tags != NULL && !gst_tag_list_is_empty (tags); - if ((tags != NULL && !gst_tag_list_is_empty (tags)) + if (has_main_tags || gst_matroska_mux_streams_have_tags (mux) || gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) { guint64 master_tags = 0, master_tag; #if 0 @@ -2991,7 +3061,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux)); #endif - if (tags != NULL) { + if (has_main_tags) { /* TODO: maybe limit via the TARGETS id by looking at the source pad */ mux->tags_pos = ebml->pos; master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS); @@ -3017,6 +3087,12 @@ gst_matroska_mux_finish (GstMatroskaMux * mux) } #endif + if (master_tags == 0 && gst_matroska_mux_streams_have_tags (mux)) { + mux->tags_pos = ebml->pos; + master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS); + } + gst_matroska_mux_write_streams_tags (mux); + if (master_tags != 0) gst_ebml_write_master_finish (ebml, master_tags); } diff --git a/gst/matroska/matroska-mux.h b/gst/matroska/matroska-mux.h index 31f4d54..48a850d 100644 --- a/gst/matroska/matroska-mux.h +++ b/gst/matroska/matroska-mux.h @@ -55,6 +55,8 @@ typedef struct _GstMatroskaMetaSeekIndex { typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps); +typedef struct _GstMatroskaMux GstMatroskaMux; + /* all information needed for one matroska stream */ typedef struct { @@ -62,6 +64,10 @@ typedef struct GstMatroskaCapsFunc capsfunc; GstMatroskaTrackContext *track; + GstMatroskaMux *mux; + + GstTagList *tags; + guint64 duration; GstClockTime start_ts; GstClockTime end_ts; /* last timestamp + (if available) duration */ @@ -70,7 +76,7 @@ typedef struct GstMatroskaPad; -typedef struct _GstMatroskaMux { +struct _GstMatroskaMux { GstElement element; /* < private > */ @@ -135,7 +141,7 @@ typedef struct _GstMatroskaMux { /* used uids */ GArray *used_uids; -} GstMatroskaMux; +}; typedef struct _GstMatroskaMuxClass { GstElementClass parent; -- 2.7.4