mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
matroskamux: store and write stream tags
Separate global from stream tags storage and write them to the appropriate tags entry in the output
This commit is contained in:
parent
75dee31b0d
commit
7772a25fdc
3 changed files with 96 additions and 13 deletions
|
@ -507,6 +507,7 @@ struct _GstMatroskaTrackContext {
|
||||||
gint index_writer_id;
|
gint index_writer_id;
|
||||||
|
|
||||||
/* some often-used info */
|
/* some often-used info */
|
||||||
|
guint64 track_uid;
|
||||||
gchar *codec_id, *codec_name, *name, *language;
|
gchar *codec_id, *codec_name, *name, *language;
|
||||||
gpointer codec_priv;
|
gpointer codec_priv;
|
||||||
gsize codec_priv_size;
|
gsize codec_priv_size;
|
||||||
|
|
|
@ -246,6 +246,8 @@ static gboolean flac_streamheader_to_codecdata (const GValue * streamheader,
|
||||||
static void
|
static void
|
||||||
gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
|
gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
|
||||||
gpointer data);
|
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
|
/* Cannot use boilerplate macros here because we need the full init function
|
||||||
* signature with the additional class argument, so we use the right template
|
* 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->codec_priv);
|
||||||
g_free (collect_pad->track);
|
g_free (collect_pad->track);
|
||||||
collect_pad->track = NULL;
|
collect_pad->track = NULL;
|
||||||
|
if (collect_pad->tags) {
|
||||||
|
gst_tag_list_unref (collect_pad->tags);
|
||||||
|
collect_pad->tags = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!full && type != 0) {
|
if (!full && type != 0) {
|
||||||
|
@ -586,12 +592,15 @@ gst_matroska_pad_reset (GstMatroskaPad * collect_pad, gboolean full)
|
||||||
|
|
||||||
context->type = type;
|
context->type = type;
|
||||||
context->name = name;
|
context->name = name;
|
||||||
|
context->track_uid = gst_matroska_mux_create_uid (collect_pad->mux);
|
||||||
/* TODO: check default values for the context */
|
/* TODO: check default values for the context */
|
||||||
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
|
context->flags = GST_MATROSKA_TRACK_ENABLED | GST_MATROSKA_TRACK_DEFAULT;
|
||||||
collect_pad->track = context;
|
collect_pad->track = context;
|
||||||
collect_pad->duration = 0;
|
collect_pad->duration = 0;
|
||||||
collect_pad->start_ts = GST_CLOCK_TIME_NONE;
|
collect_pad->start_ts = GST_CLOCK_TIME_NONE;
|
||||||
collect_pad->end_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? */
|
/* FIXME: what about stream-specific tags? */
|
||||||
gst_tag_setter_merge_tags (GST_TAG_SETTER (mux), list,
|
if (gst_tag_list_get_scope (list) == GST_TAG_SCOPE_GLOBAL) {
|
||||||
gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (mux)));
|
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);
|
gst_event_unref (event);
|
||||||
/* handled this, don't want collectpads to forward it downstream */
|
/* handled this, don't want collectpads to forward it downstream */
|
||||||
|
@ -2281,6 +2294,7 @@ gst_matroska_mux_request_new_pad (GstElement * element,
|
||||||
sizeof (GstMatroskamuxPad),
|
sizeof (GstMatroskamuxPad),
|
||||||
(GstCollectDataDestroyNotify) gst_matroska_pad_free, locked);
|
(GstCollectDataDestroyNotify) gst_matroska_pad_free, locked);
|
||||||
|
|
||||||
|
collect_pad->mux = mux;
|
||||||
collect_pad->track = context;
|
collect_pad->track = context;
|
||||||
gst_matroska_pad_reset (collect_pad, FALSE);
|
gst_matroska_pad_reset (collect_pad, FALSE);
|
||||||
collect_pad->track->codec_id = id;
|
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_TRACKNUMBER, context->num);
|
||||||
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKTYPE, context->type);
|
||||||
|
|
||||||
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID,
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKUID, context->track_uid);
|
||||||
gst_matroska_mux_create_uid (mux));
|
|
||||||
if (context->default_duration) {
|
if (context->default_duration) {
|
||||||
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TRACKDEFAULTDURATION,
|
||||||
context->default_duration);
|
context->default_duration);
|
||||||
|
@ -2659,21 +2672,25 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
||||||
|
|
||||||
if (mux->streamable) {
|
if (mux->streamable) {
|
||||||
const GstTagList *tags;
|
const GstTagList *tags;
|
||||||
|
gboolean has_main_tags;
|
||||||
|
|
||||||
/* tags */
|
/* tags */
|
||||||
tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
|
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;
|
guint64 master_tags, master_tag;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mux, "Writing tags");
|
GST_DEBUG_OBJECT (mux, "Writing tags");
|
||||||
|
|
||||||
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
|
|
||||||
mux->tags_pos = ebml->pos;
|
mux->tags_pos = ebml->pos;
|
||||||
master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
|
master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
|
||||||
master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
|
if (has_main_tags) {
|
||||||
gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
|
master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
|
||||||
gst_ebml_write_master_finish (ebml, master_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);
|
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
|
#if 0
|
||||||
static void
|
static void
|
||||||
gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
|
gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
|
||||||
|
@ -2940,6 +3008,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
guint64 duration = 0;
|
guint64 duration = 0;
|
||||||
GSList *collected;
|
GSList *collected;
|
||||||
const GstTagList *tags;
|
const GstTagList *tags;
|
||||||
|
gboolean has_main_tags;
|
||||||
|
|
||||||
/* finish last cluster */
|
/* finish last cluster */
|
||||||
if (mux->cluster) {
|
if (mux->cluster) {
|
||||||
|
@ -2977,8 +3046,9 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
|
|
||||||
/* tags */
|
/* tags */
|
||||||
tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (mux));
|
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) {
|
|| gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) {
|
||||||
guint64 master_tags = 0, master_tag;
|
guint64 master_tags = 0, master_tag;
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -2991,7 +3061,7 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
|
toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (tags != NULL) {
|
if (has_main_tags) {
|
||||||
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
|
/* TODO: maybe limit via the TARGETS id by looking at the source pad */
|
||||||
mux->tags_pos = ebml->pos;
|
mux->tags_pos = ebml->pos;
|
||||||
master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
|
master_tags = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAGS);
|
||||||
|
@ -3017,6 +3087,12 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
if (master_tags != 0)
|
||||||
gst_ebml_write_master_finish (ebml, master_tags);
|
gst_ebml_write_master_finish (ebml, master_tags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ typedef struct _GstMatroskaMetaSeekIndex {
|
||||||
|
|
||||||
typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps);
|
typedef gboolean (*GstMatroskaCapsFunc) (GstPad *pad, GstCaps *caps);
|
||||||
|
|
||||||
|
typedef struct _GstMatroskaMux GstMatroskaMux;
|
||||||
|
|
||||||
/* all information needed for one matroska stream */
|
/* all information needed for one matroska stream */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -62,6 +64,10 @@ typedef struct
|
||||||
GstMatroskaCapsFunc capsfunc;
|
GstMatroskaCapsFunc capsfunc;
|
||||||
GstMatroskaTrackContext *track;
|
GstMatroskaTrackContext *track;
|
||||||
|
|
||||||
|
GstMatroskaMux *mux;
|
||||||
|
|
||||||
|
GstTagList *tags;
|
||||||
|
|
||||||
guint64 duration;
|
guint64 duration;
|
||||||
GstClockTime start_ts;
|
GstClockTime start_ts;
|
||||||
GstClockTime end_ts; /* last timestamp + (if available) duration */
|
GstClockTime end_ts; /* last timestamp + (if available) duration */
|
||||||
|
@ -70,7 +76,7 @@ typedef struct
|
||||||
GstMatroskaPad;
|
GstMatroskaPad;
|
||||||
|
|
||||||
|
|
||||||
typedef struct _GstMatroskaMux {
|
struct _GstMatroskaMux {
|
||||||
GstElement element;
|
GstElement element;
|
||||||
|
|
||||||
/* < private > */
|
/* < private > */
|
||||||
|
@ -135,7 +141,7 @@ typedef struct _GstMatroskaMux {
|
||||||
|
|
||||||
/* used uids */
|
/* used uids */
|
||||||
GArray *used_uids;
|
GArray *used_uids;
|
||||||
} GstMatroskaMux;
|
};
|
||||||
|
|
||||||
typedef struct _GstMatroskaMuxClass {
|
typedef struct _GstMatroskaMuxClass {
|
||||||
GstElementClass parent;
|
GstElementClass parent;
|
||||||
|
|
Loading…
Reference in a new issue