mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 06:46:38 +00:00
Merge branch '0.10'
Conflicts: gst/matroska/matroska-demux.c gst/matroska/matroska-mux.c gst/matroska/matroska-read-common.c gst/matroska/matroska-read-common.h
This commit is contained in:
commit
50bc831c91
5 changed files with 808 additions and 34 deletions
|
@ -419,6 +419,7 @@ gst_matroska_demux_reset (GstElement * element)
|
||||||
demux->tracks_parsed = FALSE;
|
demux->tracks_parsed = FALSE;
|
||||||
demux->common.segmentinfo_parsed = FALSE;
|
demux->common.segmentinfo_parsed = FALSE;
|
||||||
demux->common.attachments_parsed = FALSE;
|
demux->common.attachments_parsed = FALSE;
|
||||||
|
demux->common.chapters_parsed = FALSE;
|
||||||
|
|
||||||
g_list_foreach (demux->common.tags_parsed,
|
g_list_foreach (demux->common.tags_parsed,
|
||||||
(GFunc) gst_matroska_demux_free_parsed_el, NULL);
|
(GFunc) gst_matroska_demux_free_parsed_el, NULL);
|
||||||
|
@ -477,6 +478,12 @@ gst_matroska_demux_reset (GstElement * element)
|
||||||
demux->common.cached_buffer = NULL;
|
demux->common.cached_buffer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* free chapters TOC if any */
|
||||||
|
if (demux->common.toc) {
|
||||||
|
gst_toc_free (demux->common.toc);
|
||||||
|
demux->common.toc = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
demux->invalid_duration = FALSE;
|
demux->invalid_duration = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1422,6 +1429,23 @@ gst_matroska_demux_query (GstMatroskaDemux * demux, GstPad * pad,
|
||||||
GST_OBJECT_UNLOCK (demux);
|
GST_OBJECT_UNLOCK (demux);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case GST_QUERY_TOC:
|
||||||
|
{
|
||||||
|
GstToc *toc;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (demux);
|
||||||
|
if (demux->common.toc)
|
||||||
|
toc = demux->common.toc;
|
||||||
|
else
|
||||||
|
toc = gst_toc_new ();
|
||||||
|
gst_query_set_toc (query, toc, 0);
|
||||||
|
res = TRUE;
|
||||||
|
if (!demux->common.toc)
|
||||||
|
gst_toc_free (toc);
|
||||||
|
GST_OBJECT_UNLOCK (demux);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
res = gst_pad_query_default (pad, (GstObject *) demux, query);
|
res = gst_pad_query_default (pad, (GstObject *) demux, query);
|
||||||
break;
|
break;
|
||||||
|
@ -2213,6 +2237,45 @@ gst_matroska_demux_handle_src_event (GstPad * pad, GstObject * parent,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case GST_EVENT_TOC_SELECT:
|
||||||
|
{
|
||||||
|
char *uid = NULL;
|
||||||
|
GstTocEntry *entry = NULL;
|
||||||
|
GstEvent *seek_event;
|
||||||
|
gint64 start_pos;
|
||||||
|
|
||||||
|
if (!demux->common.toc) {
|
||||||
|
GST_DEBUG_OBJECT (demux, "no TOC to select");
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
gst_event_parse_toc_select (event, &uid);
|
||||||
|
if (uid != NULL) {
|
||||||
|
GST_OBJECT_LOCK (demux);
|
||||||
|
entry = gst_toc_find_entry (demux->common.toc, uid);
|
||||||
|
if (entry == NULL) {
|
||||||
|
GST_OBJECT_UNLOCK (demux);
|
||||||
|
GST_WARNING_OBJECT (demux, "no TOC entry with given UID: %s", uid);
|
||||||
|
res = FALSE;
|
||||||
|
} else {
|
||||||
|
gst_toc_entry_get_start_stop (entry, &start_pos, NULL);
|
||||||
|
GST_OBJECT_UNLOCK (demux);
|
||||||
|
seek_event = gst_event_new_seek (1.0,
|
||||||
|
GST_FORMAT_TIME,
|
||||||
|
GST_SEEK_FLAG_FLUSH,
|
||||||
|
GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_SET, -1);
|
||||||
|
res = gst_matroska_demux_handle_seek_event (demux, pad, seek_event);
|
||||||
|
gst_event_unref (seek_event);
|
||||||
|
}
|
||||||
|
g_free (uid);
|
||||||
|
} else {
|
||||||
|
GST_WARNING_OBJECT (demux, "received empty TOC select event");
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gst_event_unref (event);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* events we don't need to handle */
|
/* events we don't need to handle */
|
||||||
case GST_EVENT_NAVIGATION:
|
case GST_EVENT_NAVIGATION:
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
|
@ -4281,8 +4344,20 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
|
||||||
GST_ELEMENT_CAST (demux), &ebml);
|
GST_ELEMENT_CAST (demux), &ebml);
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_CHAPTERS:
|
case GST_MATROSKA_ID_CHAPTERS:
|
||||||
|
if (!demux->common.chapters_parsed) {
|
||||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||||
ret = gst_matroska_read_common_parse_chapters (&demux->common, &ebml);
|
ret =
|
||||||
|
gst_matroska_read_common_parse_chapters (&demux->common, &ebml);
|
||||||
|
|
||||||
|
if (demux->common.toc) {
|
||||||
|
gst_matroska_demux_send_event (demux,
|
||||||
|
gst_event_new_toc (demux->common.toc, FALSE));
|
||||||
|
gst_element_post_message (GST_ELEMENT_CAST (demux),
|
||||||
|
gst_message_new_toc (GST_OBJECT_CAST (demux),
|
||||||
|
demux->common.toc, FALSE));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
GST_READ_CHECK (gst_matroska_demux_flush (demux, read));
|
||||||
break;
|
break;
|
||||||
case GST_MATROSKA_ID_SEEKHEAD:
|
case GST_MATROSKA_ID_SEEKHEAD:
|
||||||
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
|
||||||
|
|
|
@ -57,6 +57,8 @@
|
||||||
#include "matroska-mux.h"
|
#include "matroska-mux.h"
|
||||||
#include "matroska-ids.h"
|
#include "matroska-ids.h"
|
||||||
|
|
||||||
|
#define GST_MATROSKA_MUX_CHAPLANG "und"
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
|
GST_DEBUG_CATEGORY_STATIC (matroskamux_debug);
|
||||||
#define GST_CAT_DEFAULT matroskamux_debug
|
#define GST_CAT_DEFAULT matroskamux_debug
|
||||||
|
|
||||||
|
@ -198,7 +200,9 @@ G_LOCK_DEFINE_STATIC (used_uids);
|
||||||
|
|
||||||
#define parent_class gst_matroska_mux_parent_class
|
#define parent_class gst_matroska_mux_parent_class
|
||||||
G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
|
G_DEFINE_TYPE_WITH_CODE (GstMatroskaMux, gst_matroska_mux, GST_TYPE_ELEMENT,
|
||||||
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL)
|
||||||
|
G_IMPLEMENT_INTERFACE (GST_TYPE_TOC_SETTER, NULL)
|
||||||
|
);
|
||||||
|
|
||||||
/* Matroska muxer destructor */
|
/* Matroska muxer destructor */
|
||||||
static void gst_matroska_mux_finalize (GObject * object);
|
static void gst_matroska_mux_finalize (GObject * object);
|
||||||
|
@ -638,6 +642,13 @@ gst_matroska_mux_reset (GstElement * element)
|
||||||
|
|
||||||
/* reset tags */
|
/* reset tags */
|
||||||
gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
|
gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
|
||||||
|
|
||||||
|
mux->tags_pos = 0;
|
||||||
|
|
||||||
|
/* reset chapters */
|
||||||
|
gst_toc_setter_reset_toc (GST_TOC_SETTER (mux));
|
||||||
|
|
||||||
|
mux->chapters_pos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -797,6 +808,30 @@ gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case GST_EVENT_TOC:{
|
||||||
|
GstToc *toc;
|
||||||
|
|
||||||
|
if (mux->chapters_pos > 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (mux, "received toc event");
|
||||||
|
gst_event_parse_toc (event, &toc, NULL);
|
||||||
|
|
||||||
|
if (toc != NULL) {
|
||||||
|
if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) {
|
||||||
|
gst_toc_setter_reset_toc (GST_TOC_SETTER (mux));
|
||||||
|
GST_INFO_OBJECT (pad, "Replacing TOC with a new one");
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_toc_setter_set_toc (GST_TOC_SETTER (mux), toc);
|
||||||
|
gst_toc_free (toc);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_event_unref (event);
|
||||||
|
/* handled this, don't want collectpads to forward it downstream */
|
||||||
|
event = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case GST_EVENT_CUSTOM_DOWNSTREAM:{
|
case GST_EVENT_CUSTOM_DOWNSTREAM:{
|
||||||
const GstStructure *structure;
|
const GstStructure *structure;
|
||||||
|
|
||||||
|
@ -2314,6 +2349,110 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
|
||||||
context->codec_priv, context->codec_priv_size);
|
context->codec_priv, context->codec_priv_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_matroska_mux_write_chapter_title (const gchar * title, GstEbmlWrite * ebml)
|
||||||
|
{
|
||||||
|
guint64 title_master;
|
||||||
|
|
||||||
|
title_master =
|
||||||
|
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERDISPLAY);
|
||||||
|
|
||||||
|
gst_ebml_write_utf8 (ebml, GST_MATROSKA_ID_CHAPSTRING, title);
|
||||||
|
gst_ebml_write_ascii (ebml, GST_MATROSKA_ID_CHAPLANGUAGE,
|
||||||
|
GST_MATROSKA_MUX_CHAPLANG);
|
||||||
|
|
||||||
|
gst_ebml_write_master_finish (ebml, title_master);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_matroska_mux_write_chapter (GstMatroskaMux * mux, GstTocEntry * edition,
|
||||||
|
GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters,
|
||||||
|
guint64 * master_edition)
|
||||||
|
{
|
||||||
|
guint64 uid, master_chapteratom;
|
||||||
|
GList *cur;
|
||||||
|
GstTocEntry *cur_entry;
|
||||||
|
guint count, i;
|
||||||
|
gchar *title;
|
||||||
|
gint64 start, stop;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (master_chapters != NULL && *master_chapters == 0))
|
||||||
|
*master_chapters =
|
||||||
|
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERS);
|
||||||
|
|
||||||
|
if (G_UNLIKELY (master_edition != NULL && *master_edition == 0)) {
|
||||||
|
/* create uid for the parent */
|
||||||
|
uid = gst_matroska_mux_create_uid ();
|
||||||
|
g_free (edition->uid);
|
||||||
|
edition->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
|
||||||
|
|
||||||
|
*master_edition =
|
||||||
|
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_EDITIONENTRY);
|
||||||
|
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONUID, uid);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGHIDDEN, 0);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGDEFAULT, 0);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_EDITIONFLAGORDERED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uid = gst_matroska_mux_create_uid ();
|
||||||
|
gst_toc_entry_get_start_stop (entry, &start, &stop);
|
||||||
|
|
||||||
|
master_chapteratom =
|
||||||
|
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_CHAPTERATOM);
|
||||||
|
g_free (entry->uid);
|
||||||
|
entry->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERUID, uid);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTART, start);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERTIMESTOP, stop);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGHIDDEN, 0);
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_CHAPTERFLAGENABLED, 1);
|
||||||
|
|
||||||
|
cur = entry->subentries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
cur_entry = cur->data;
|
||||||
|
gst_matroska_mux_write_chapter (mux, NULL, cur_entry, ebml, NULL, NULL);
|
||||||
|
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_LIKELY (entry->tags != NULL)) {
|
||||||
|
count = gst_tag_list_get_tag_size (entry->tags, GST_TAG_TITLE);
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
gst_tag_list_get_string_index (entry->tags, GST_TAG_TITLE, i, &title);
|
||||||
|
gst_matroska_mux_write_chapter_title (title, ebml);
|
||||||
|
g_free (title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove title tag */
|
||||||
|
if (G_LIKELY (count > 0))
|
||||||
|
gst_tag_list_remove_tag (entry->tags, GST_TAG_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_ebml_write_master_finish (ebml, master_chapteratom);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_matroska_mux_write_chapter_edition (GstMatroskaMux * mux,
|
||||||
|
GstTocEntry * entry, GstEbmlWrite * ebml, guint64 * master_chapters)
|
||||||
|
{
|
||||||
|
guint64 master_edition = 0;
|
||||||
|
GList *cur;
|
||||||
|
GstTocEntry *subentry;
|
||||||
|
|
||||||
|
cur = entry->subentries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
subentry = cur->data;
|
||||||
|
gst_matroska_mux_write_chapter (mux, entry, subentry, ebml, master_chapters,
|
||||||
|
&master_edition);
|
||||||
|
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (G_LIKELY (master_edition != 0))
|
||||||
|
gst_ebml_write_master_finish (ebml, master_edition);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_matroska_mux_start:
|
* gst_matroska_mux_start:
|
||||||
|
@ -2328,6 +2467,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
||||||
const gchar *doctype;
|
const gchar *doctype;
|
||||||
guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
|
guint32 seekhead_id[] = { GST_MATROSKA_ID_SEGMENTINFO,
|
||||||
GST_MATROSKA_ID_TRACKS,
|
GST_MATROSKA_ID_TRACKS,
|
||||||
|
GST_MATROSKA_ID_CHAPTERS,
|
||||||
GST_MATROSKA_ID_CUES,
|
GST_MATROSKA_ID_CUES,
|
||||||
GST_MATROSKA_ID_TAGS,
|
GST_MATROSKA_ID_TAGS,
|
||||||
0
|
0
|
||||||
|
@ -2487,6 +2627,68 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
|
||||||
}
|
}
|
||||||
gst_ebml_write_master_finish (ebml, master);
|
gst_ebml_write_master_finish (ebml, master);
|
||||||
|
|
||||||
|
/* chapters */
|
||||||
|
if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL && !mux->streamable) {
|
||||||
|
guint64 master_chapters = 0;
|
||||||
|
GstTocEntry *toc_entry;
|
||||||
|
const GstToc *toc;
|
||||||
|
GList *cur, *to_write = NULL;
|
||||||
|
gint64 start, stop;
|
||||||
|
|
||||||
|
GST_DEBUG ("Writing chapters");
|
||||||
|
|
||||||
|
toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
|
||||||
|
|
||||||
|
/* check whether we have editions or chapters at the root level */
|
||||||
|
toc_entry = toc->entries->data;
|
||||||
|
|
||||||
|
if (toc_entry->type != GST_TOC_ENTRY_TYPE_EDITION) {
|
||||||
|
toc_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, "");
|
||||||
|
gst_toc_entry_set_start_stop (toc_entry, -1, -1);
|
||||||
|
|
||||||
|
/* aggregate all chapters without root edition */
|
||||||
|
cur = toc->entries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
toc_entry->subentries =
|
||||||
|
g_list_prepend (toc_entry->subentries, cur->data);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_toc_entry_get_start_stop (((GstTocEntry *) toc_entry->
|
||||||
|
subentries->data), &start, NULL);
|
||||||
|
toc_entry->subentries = g_list_reverse (toc_entry->subentries);
|
||||||
|
gst_toc_entry_get_start_stop (((GstTocEntry *) toc_entry->
|
||||||
|
subentries->data), NULL, &stop);
|
||||||
|
gst_toc_entry_set_start_stop (toc_entry, start, stop);
|
||||||
|
|
||||||
|
to_write = g_list_append (to_write, toc_entry);
|
||||||
|
} else {
|
||||||
|
toc_entry = NULL;
|
||||||
|
to_write = toc->entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finally write chapters */
|
||||||
|
mux->chapters_pos = ebml->pos;
|
||||||
|
|
||||||
|
cur = to_write;
|
||||||
|
while (cur != NULL) {
|
||||||
|
gst_matroska_mux_write_chapter_edition (mux, cur->data, ebml,
|
||||||
|
&master_chapters);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close master element if any edition was written */
|
||||||
|
if (G_LIKELY (master_chapters != 0))
|
||||||
|
gst_ebml_write_master_finish (ebml, master_chapters);
|
||||||
|
|
||||||
|
if (toc_entry != NULL) {
|
||||||
|
g_list_free (toc_entry->subentries);
|
||||||
|
toc_entry->subentries = NULL;
|
||||||
|
gst_toc_entry_free (toc_entry);
|
||||||
|
g_list_free (to_write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* lastly, flush the cache */
|
/* lastly, flush the cache */
|
||||||
gst_ebml_write_flush_cache (ebml, FALSE, 0);
|
gst_ebml_write_flush_cache (ebml, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
@ -2550,6 +2752,44 @@ gst_matroska_mux_write_simple_tag (const GstTagList * list, const gchar * tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_matroska_mux_write_toc_entry_tags (GstMatroskaMux * mux,
|
||||||
|
const GstTocEntry * entry, guint64 * master_tags)
|
||||||
|
{
|
||||||
|
guint64 master_tag, master_targets;
|
||||||
|
GstEbmlWrite *ebml;
|
||||||
|
GList *cur;
|
||||||
|
|
||||||
|
ebml = mux->ebml_write;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (entry->tags != NULL && !gst_tag_list_is_empty (entry->tags))) {
|
||||||
|
if (*master_tags == 0) {
|
||||||
|
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);
|
||||||
|
master_targets =
|
||||||
|
gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TARGETS);
|
||||||
|
|
||||||
|
if (entry->type == GST_TOC_ENTRY_TYPE_EDITION)
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETEDITIONUID,
|
||||||
|
g_ascii_strtoull (entry->uid, NULL, 10));
|
||||||
|
else
|
||||||
|
gst_ebml_write_uint (ebml, GST_MATROSKA_ID_TARGETCHAPTERUID,
|
||||||
|
g_ascii_strtoull (entry->uid, NULL, 10));
|
||||||
|
|
||||||
|
gst_ebml_write_master_finish (ebml, master_targets);
|
||||||
|
gst_tag_list_foreach (entry->tags, gst_matroska_mux_write_simple_tag, ebml);
|
||||||
|
gst_ebml_write_master_finish (ebml, master_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = entry->subentries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
gst_matroska_mux_write_toc_entry_tags (mux, cur->data, master_tags);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_matroska_mux_finish:
|
* gst_matroska_mux_finish:
|
||||||
|
@ -2603,22 +2843,45 @@ 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));
|
||||||
|
|
||||||
if (tags != NULL && !gst_tag_list_is_empty (tags)) {
|
if ((tags != NULL && !gst_tag_list_is_empty (tags))
|
||||||
guint64 master_tags, master_tag;
|
|| gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL) {
|
||||||
|
guint64 master_tags = 0, master_tag;
|
||||||
|
GList *cur;
|
||||||
|
const GstToc *toc;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (mux, "Writing tags");
|
GST_DEBUG_OBJECT (mux, "Writing tags");
|
||||||
|
|
||||||
|
toc = gst_toc_setter_get_toc (GST_TOC_SETTER (mux));
|
||||||
|
|
||||||
|
if (tags != NULL) {
|
||||||
/* 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);
|
||||||
master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
|
master_tag = gst_ebml_write_master_start (ebml, GST_MATROSKA_ID_TAG);
|
||||||
|
|
||||||
|
if (tags != NULL)
|
||||||
gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
|
gst_tag_list_foreach (tags, gst_matroska_mux_write_simple_tag, ebml);
|
||||||
|
if (toc != NULL)
|
||||||
|
gst_tag_list_foreach (toc->tags, gst_matroska_mux_write_simple_tag,
|
||||||
|
ebml);
|
||||||
|
|
||||||
gst_ebml_write_master_finish (ebml, master_tag);
|
gst_ebml_write_master_finish (ebml, master_tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toc != NULL) {
|
||||||
|
cur = toc->entries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
gst_matroska_mux_write_toc_entry_tags (mux, cur->data, &master_tags);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (master_tags != 0)
|
||||||
gst_ebml_write_master_finish (ebml, master_tags);
|
gst_ebml_write_master_finish (ebml, master_tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update seekhead. We know that:
|
/* update seekhead. We know that:
|
||||||
* - a seekhead contains 4 entries.
|
* - a seekhead contains 5 entries.
|
||||||
* - order of entries is as above.
|
* - order of entries is as above.
|
||||||
* - a seekhead has a 4-byte header + 8-byte length
|
* - a seekhead has a 4-byte header + 8-byte length
|
||||||
* - each entry is 2-byte master, 2-byte ID pointer,
|
* - each entry is 2-byte master, 2-byte ID pointer,
|
||||||
|
@ -2631,9 +2894,10 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
mux->info_pos - mux->segment_master);
|
mux->info_pos - mux->segment_master);
|
||||||
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
|
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 60,
|
||||||
mux->tracks_pos - mux->segment_master);
|
mux->tracks_pos - mux->segment_master);
|
||||||
if (mux->index != NULL) {
|
if (gst_toc_setter_get_toc (GST_TOC_SETTER (mux)) != NULL
|
||||||
|
&& mux->chapters_pos > 0) {
|
||||||
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
|
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 88,
|
||||||
mux->cues_pos - mux->segment_master);
|
mux->chapters_pos - mux->segment_master);
|
||||||
} else {
|
} else {
|
||||||
/* void'ify */
|
/* void'ify */
|
||||||
guint64 my_pos = ebml->pos;
|
guint64 my_pos = ebml->pos;
|
||||||
|
@ -2642,9 +2906,9 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
|
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
|
||||||
gst_ebml_write_seek (ebml, my_pos);
|
gst_ebml_write_seek (ebml, my_pos);
|
||||||
}
|
}
|
||||||
if (tags != NULL) {
|
if (mux->index != NULL) {
|
||||||
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
|
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 116,
|
||||||
mux->tags_pos - mux->segment_master);
|
mux->cues_pos - mux->segment_master);
|
||||||
} else {
|
} else {
|
||||||
/* void'ify */
|
/* void'ify */
|
||||||
guint64 my_pos = ebml->pos;
|
guint64 my_pos = ebml->pos;
|
||||||
|
@ -2654,6 +2918,18 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
|
||||||
gst_ebml_write_seek (ebml, my_pos);
|
gst_ebml_write_seek (ebml, my_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tags != NULL) {
|
||||||
|
gst_ebml_replace_uint (ebml, mux->seekhead_pos + 144,
|
||||||
|
mux->tags_pos - mux->segment_master);
|
||||||
|
} else {
|
||||||
|
/* void'ify */
|
||||||
|
guint64 my_pos = ebml->pos;
|
||||||
|
|
||||||
|
gst_ebml_write_seek (ebml, mux->seekhead_pos + 124);
|
||||||
|
gst_ebml_write_buffer_header (ebml, GST_EBML_ID_VOID, 26);
|
||||||
|
gst_ebml_write_seek (ebml, my_pos);
|
||||||
|
}
|
||||||
|
|
||||||
/* loop tracks:
|
/* loop tracks:
|
||||||
* - first get the overall duration
|
* - first get the overall duration
|
||||||
* (a released track may have left a duration in here)
|
* (a released track may have left a duration in here)
|
||||||
|
|
|
@ -113,6 +113,7 @@ typedef struct _GstMatroskaMux {
|
||||||
guint64 segment_pos,
|
guint64 segment_pos,
|
||||||
seekhead_pos,
|
seekhead_pos,
|
||||||
cues_pos,
|
cues_pos,
|
||||||
|
chapters_pos,
|
||||||
tags_pos,
|
tags_pos,
|
||||||
info_pos,
|
info_pos,
|
||||||
tracks_pos,
|
tracks_pos,
|
||||||
|
@ -128,7 +129,6 @@ typedef struct _GstMatroskaMux {
|
||||||
|
|
||||||
/* GstForceKeyUnit event */
|
/* GstForceKeyUnit event */
|
||||||
GstEvent *force_key_unit_event;
|
GstEvent *force_key_unit_event;
|
||||||
|
|
||||||
} GstMatroskaMux;
|
} GstMatroskaMux;
|
||||||
|
|
||||||
typedef struct _GstMatroskaMuxClass {
|
typedef struct _GstMatroskaMuxClass {
|
||||||
|
|
|
@ -56,6 +56,10 @@ GST_DEBUG_CATEGORY (matroskareadcommon_debug);
|
||||||
GST_DEBUG_OBJECT (common, "Parsing " element " element " \
|
GST_DEBUG_OBJECT (common, "Parsing " element " element " \
|
||||||
" finished with '%s'", gst_flow_get_name (ret))
|
" finished with '%s'", gst_flow_get_name (ret))
|
||||||
|
|
||||||
|
#define GST_MATROSKA_TOC_UID_CHAPTER "chapter"
|
||||||
|
#define GST_MATROSKA_TOC_UID_EDITION "edition"
|
||||||
|
#define GST_MATROSKA_TOC_UID_EMPTY "empty"
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
|
gst_matroska_decompress_data (GstMatroskaTrackEncoding * enc,
|
||||||
gpointer * data_out, gsize * size_out,
|
gpointer * data_out, gsize * size_out,
|
||||||
|
@ -711,21 +715,53 @@ gst_matroska_read_common_parse_attachments (GstMatroskaReadCommon * common,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn
|
static void
|
||||||
gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
|
gst_matroska_read_common_parse_toc_tag (GstTocEntry * entry,
|
||||||
GstEbmlRead * ebml)
|
GArray * edition_targets, GArray * chapter_targtes, GstTagList * tags)
|
||||||
|
{
|
||||||
|
gchar *uid;
|
||||||
|
guint i;
|
||||||
|
guint64 tgt;
|
||||||
|
GArray *targets;
|
||||||
|
GList *cur;
|
||||||
|
|
||||||
|
targets =
|
||||||
|
(entry->type ==
|
||||||
|
GST_TOC_ENTRY_TYPE_EDITION) ? edition_targets : chapter_targtes;
|
||||||
|
|
||||||
|
for (i = 0; i < targets->len; ++i) {
|
||||||
|
tgt = g_array_index (targets, guint64, i);
|
||||||
|
|
||||||
|
if (tgt == 0)
|
||||||
|
gst_tag_list_insert (entry->tags, tags, GST_TAG_MERGE_APPEND);
|
||||||
|
else {
|
||||||
|
uid = g_strdup_printf ("%" G_GUINT64_FORMAT, tgt);
|
||||||
|
if (g_strcmp0 (entry->uid, uid) == 0)
|
||||||
|
gst_tag_list_insert (entry->tags, tags, GST_TAG_MERGE_APPEND);
|
||||||
|
g_free (uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = entry->subentries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
gst_matroska_read_common_parse_toc_tag (cur->data, edition_targets,
|
||||||
|
chapter_targtes, tags);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_metadata_targets (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml, GArray * edition_targets, GArray * chapter_targets)
|
||||||
{
|
{
|
||||||
guint32 id;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
guint32 id;
|
||||||
|
guint64 uid;
|
||||||
|
|
||||||
GST_WARNING_OBJECT (common, "Parsing of chapters not implemented yet");
|
DEBUG_ELEMENT_START (common, ebml, "TagTargets");
|
||||||
|
|
||||||
/* TODO: implement parsing of chapters */
|
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (common, ebml, "Chapters");
|
|
||||||
|
|
||||||
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
|
DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,12 +770,358 @@ gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case GST_MATROSKA_ID_TARGETCHAPTERUID:
|
||||||
|
if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
|
||||||
|
g_array_append_val (chapter_targets, uid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_TARGETEDITIONUID:
|
||||||
|
if ((ret = gst_ebml_read_uint (ebml, &id, &uid)) == GST_FLOW_OK)
|
||||||
|
g_array_append_val (edition_targets, uid);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = gst_ebml_read_skip (ebml);
|
ret =
|
||||||
|
gst_matroska_read_common_parse_skip (common, ebml, "TagTargets",
|
||||||
|
id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "TagTargets", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_matroska_read_common_postprocess_toc_entries (GList * toc_entries,
|
||||||
|
guint64 max, const gchar * parent_uid)
|
||||||
|
{
|
||||||
|
GstTocEntry *cur_info, *prev_info, *next_info;
|
||||||
|
GList *cur_list, *prev_list, *next_list;
|
||||||
|
gchar *iter_digit;
|
||||||
|
gint i = 0;
|
||||||
|
gint64 cur_start, prev_start, stop;
|
||||||
|
|
||||||
|
cur_list = toc_entries;
|
||||||
|
while (cur_list != NULL) {
|
||||||
|
++i;
|
||||||
|
cur_info = cur_list->data;
|
||||||
|
|
||||||
|
iter_digit = g_strdup_printf ("%d", i);
|
||||||
|
|
||||||
|
switch (cur_info->type) {
|
||||||
|
case GST_TOC_ENTRY_TYPE_EDITION:
|
||||||
|
/* in Matroska terms edition has duration of full track */
|
||||||
|
gst_toc_entry_set_start_stop (cur_info, 0, max);
|
||||||
|
|
||||||
|
if (cur_info->uid == NULL)
|
||||||
|
cur_info->uid =
|
||||||
|
g_strconcat (parent_uid, "/", GST_MATROSKA_TOC_UID_EDITION,
|
||||||
|
iter_digit, NULL);
|
||||||
|
|
||||||
|
gst_matroska_read_common_postprocess_toc_entries (cur_info->subentries,
|
||||||
|
max, cur_info->uid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_TOC_ENTRY_TYPE_CHAPTER:
|
||||||
|
prev_list = cur_list->prev;
|
||||||
|
next_list = cur_list->next;
|
||||||
|
|
||||||
|
if (prev_list != NULL)
|
||||||
|
prev_info = prev_list->data;
|
||||||
|
else
|
||||||
|
prev_info = NULL;
|
||||||
|
|
||||||
|
if (next_list != NULL)
|
||||||
|
next_info = next_list->data;
|
||||||
|
else
|
||||||
|
next_info = NULL;
|
||||||
|
|
||||||
|
if (cur_info->uid == NULL)
|
||||||
|
cur_info->uid =
|
||||||
|
g_strconcat (parent_uid, "/", GST_MATROSKA_TOC_UID_CHAPTER,
|
||||||
|
iter_digit, NULL);
|
||||||
|
|
||||||
|
/* updated stop time in previous chapter and it's subchapters */
|
||||||
|
if (prev_info != NULL) {
|
||||||
|
gst_toc_entry_get_start_stop (prev_info, &prev_start, &stop);
|
||||||
|
gst_toc_entry_get_start_stop (cur_info, &cur_start, &stop);
|
||||||
|
|
||||||
|
stop = cur_start;
|
||||||
|
gst_toc_entry_set_start_stop (prev_info, prev_start, stop);
|
||||||
|
|
||||||
|
gst_matroska_read_common_postprocess_toc_entries
|
||||||
|
(prev_info->subentries, cur_start, prev_info->uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* updated stop time in current chapter and it's subchapters */
|
||||||
|
if (next_info == NULL) {
|
||||||
|
gst_toc_entry_get_start_stop (cur_info, &cur_start, &stop);
|
||||||
|
|
||||||
|
if (stop == -1) {
|
||||||
|
stop = max;
|
||||||
|
gst_toc_entry_set_start_stop (cur_info, cur_start, stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_matroska_read_common_postprocess_toc_entries
|
||||||
|
(cur_info->subentries, stop, cur_info->uid);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_list = cur_list->next;
|
||||||
|
g_free (iter_digit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_chapter_titles (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml, GstTagList * titles)
|
||||||
|
{
|
||||||
|
guint32 id;
|
||||||
|
gchar *title = NULL;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "ChaptersTitles");
|
||||||
|
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case GST_MATROSKA_ID_CHAPSTRING:
|
||||||
|
ret = gst_ebml_read_utf8 (ebml, &id, &title);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_skip (common, ebml, "ChaptersTitles",
|
||||||
|
id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersTitles", ret);
|
||||||
|
|
||||||
|
if (title != NULL && ret == GST_FLOW_OK)
|
||||||
|
gst_tag_list_add (titles, GST_TAG_MERGE_APPEND, GST_TAG_TITLE, title, NULL);
|
||||||
|
|
||||||
|
g_free (title);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_chapter_element (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml, GstTocEntry * toc_entry)
|
||||||
|
{
|
||||||
|
guint32 id;
|
||||||
|
guint64 start_time = -1, stop_time = -1;
|
||||||
|
guint64 is_hidden = 0, is_enabled = 1, uid = 0;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
GstTocEntry *chapter_info;
|
||||||
|
GstTagList *titles;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "ChaptersElement");
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
titles = gst_tag_list_new ();
|
||||||
|
chapter_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER,
|
||||||
|
GST_MATROSKA_TOC_UID_EMPTY);
|
||||||
|
|
||||||
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case GST_MATROSKA_ID_CHAPTERUID:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &uid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERTIMESTART:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &start_time);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERTIMESTOP:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &stop_time);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERATOM:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_chapter_element (common, ebml,
|
||||||
|
chapter_info);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERDISPLAY:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_chapter_titles (common, ebml,
|
||||||
|
titles);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERFLAGHIDDEN:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERFLAGENABLED:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &is_enabled);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_skip (common, ebml,
|
||||||
|
"ChaptersElement", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_toc_entry_set_start_stop (chapter_info, start_time, stop_time);
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersElement", ret);
|
||||||
|
|
||||||
|
g_free (chapter_info->uid);
|
||||||
|
|
||||||
|
if (uid != 0)
|
||||||
|
chapter_info->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
|
||||||
|
else
|
||||||
|
chapter_info->uid = NULL;
|
||||||
|
|
||||||
|
/* start time is mandatory and has no default value,
|
||||||
|
* so we should skip chapters without it */
|
||||||
|
if (is_hidden == 0 && is_enabled > 0 &&
|
||||||
|
start_time != -1 && ret == GST_FLOW_OK) {
|
||||||
|
if (!gst_tag_list_is_empty (titles))
|
||||||
|
gst_tag_list_insert (chapter_info->tags, titles, GST_TAG_MERGE_APPEND);
|
||||||
|
|
||||||
|
toc_entry->subentries = g_list_append (toc_entry->subentries, chapter_info);
|
||||||
|
} else
|
||||||
|
gst_toc_entry_free (chapter_info);
|
||||||
|
|
||||||
|
gst_tag_list_free (titles);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_chapter_edition (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml, GstToc * toc)
|
||||||
|
{
|
||||||
|
guint32 id;
|
||||||
|
guint64 is_hidden = 0, uid = 0;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
GstTocEntry *edition_info;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "ChaptersEdition");
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
edition_info = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION,
|
||||||
|
GST_MATROSKA_TOC_UID_EMPTY);
|
||||||
|
|
||||||
|
gst_toc_entry_set_start_stop (edition_info, -1, -1);
|
||||||
|
|
||||||
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case GST_MATROSKA_ID_EDITIONUID:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &uid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_CHAPTERATOM:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_chapter_element (common, ebml,
|
||||||
|
edition_info);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_EDITIONFLAGHIDDEN:
|
||||||
|
ret = gst_ebml_read_uint (ebml, &id, &is_hidden);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_skip (common, ebml,
|
||||||
|
"ChaptersEdition", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "ChaptersEdition", ret);
|
||||||
|
|
||||||
|
g_free (edition_info->uid);
|
||||||
|
|
||||||
|
if (uid != 0)
|
||||||
|
edition_info->uid = g_strdup_printf ("%" G_GUINT64_FORMAT, uid);
|
||||||
|
else
|
||||||
|
edition_info->uid = NULL;
|
||||||
|
|
||||||
|
if (is_hidden == 0 && edition_info->subentries != NULL && ret == GST_FLOW_OK)
|
||||||
|
toc->entries = g_list_prepend (toc->entries, edition_info);
|
||||||
|
else {
|
||||||
|
GST_DEBUG_OBJECT (common,
|
||||||
|
"Skipping empty or hidden edition in the chapters TOC");
|
||||||
|
gst_toc_entry_free (edition_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstFlowReturn
|
||||||
|
gst_matroska_read_common_parse_chapters (GstMatroskaReadCommon * common,
|
||||||
|
GstEbmlRead * ebml)
|
||||||
|
{
|
||||||
|
guint32 id;
|
||||||
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
GstToc *toc;
|
||||||
|
|
||||||
|
DEBUG_ELEMENT_START (common, ebml, "Chapters");
|
||||||
|
|
||||||
|
if ((ret = gst_ebml_read_master (ebml, &id)) != GST_FLOW_OK) {
|
||||||
|
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
toc = gst_toc_new ();
|
||||||
|
|
||||||
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case GST_MATROSKA_ID_EDITIONENTRY:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_chapter_edition (common, ebml, toc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_skip (common, ebml, "Chapters", id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toc->entries != NULL) {
|
||||||
|
toc->entries = g_list_reverse (toc->entries);
|
||||||
|
gst_matroska_read_common_postprocess_toc_entries (toc->entries,
|
||||||
|
common->segment.duration, "");
|
||||||
|
|
||||||
|
common->toc = toc;
|
||||||
|
} else
|
||||||
|
gst_toc_free (toc);
|
||||||
|
|
||||||
|
common->chapters_parsed = TRUE;
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
|
DEBUG_ELEMENT_STOP (common, ebml, "Chapters", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1487,6 +1869,9 @@ gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
|
||||||
{
|
{
|
||||||
guint32 id;
|
guint32 id;
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
|
GArray *chapter_targets, *edition_targets;
|
||||||
|
GstTagList *taglist;
|
||||||
|
GList *cur;
|
||||||
|
|
||||||
DEBUG_ELEMENT_START (common, ebml, "Tag");
|
DEBUG_ELEMENT_START (common, ebml, "Tag");
|
||||||
|
|
||||||
|
@ -1495,6 +1880,10 @@ gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edition_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||||
|
chapter_targets = g_array_new (FALSE, FALSE, sizeof (guint64));
|
||||||
|
taglist = gst_tag_list_new ();
|
||||||
|
|
||||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
/* read all sub-entries */
|
/* read all sub-entries */
|
||||||
|
|
||||||
|
@ -1504,7 +1893,13 @@ gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case GST_MATROSKA_ID_SIMPLETAG:
|
case GST_MATROSKA_ID_SIMPLETAG:
|
||||||
ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
|
ret = gst_matroska_read_common_parse_metadata_id_simple_tag (common,
|
||||||
ebml, p_taglist);
|
ebml, &taglist);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GST_MATROSKA_ID_TARGETS:
|
||||||
|
ret =
|
||||||
|
gst_matroska_read_common_parse_metadata_targets (common, ebml,
|
||||||
|
edition_targets, chapter_targets);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1515,6 +1910,27 @@ gst_matroska_read_common_parse_metadata_id_tag (GstMatroskaReadCommon * common,
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
|
DEBUG_ELEMENT_STOP (common, ebml, "Tag", ret);
|
||||||
|
|
||||||
|
/* if tag is chapter/edition specific - try to find that entry */
|
||||||
|
if (G_UNLIKELY (chapter_targets->len > 0 || edition_targets->len > 0)) {
|
||||||
|
if (common->toc == NULL)
|
||||||
|
GST_WARNING_OBJECT (common,
|
||||||
|
"Found chapter/edition specific tag, but TOC doesn't present");
|
||||||
|
else {
|
||||||
|
cur = common->toc->entries;
|
||||||
|
while (cur != NULL) {
|
||||||
|
gst_matroska_read_common_parse_toc_tag (cur->data, edition_targets,
|
||||||
|
chapter_targets, taglist);
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
common->toc_updated = TRUE;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
gst_tag_list_insert (*p_taglist, taglist, GST_TAG_MERGE_APPEND);
|
||||||
|
|
||||||
|
gst_tag_list_free (taglist);
|
||||||
|
g_array_unref (chapter_targets);
|
||||||
|
g_array_unref (edition_targets);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1554,6 +1970,7 @@ gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
|
||||||
}
|
}
|
||||||
|
|
||||||
taglist = gst_tag_list_new_empty ();
|
taglist = gst_tag_list_new_empty ();
|
||||||
|
common->toc_updated = FALSE;
|
||||||
|
|
||||||
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
while (ret == GST_FLOW_OK && gst_ebml_read_has_remaining (ebml, 1, TRUE)) {
|
||||||
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
if ((ret = gst_ebml_peek_id (ebml, &id)) != GST_FLOW_OK)
|
||||||
|
@ -1569,15 +1986,15 @@ gst_matroska_read_common_parse_metadata (GstMatroskaReadCommon * common,
|
||||||
ret = gst_matroska_read_common_parse_skip (common, ebml, "Tags", id);
|
ret = gst_matroska_read_common_parse_skip (common, ebml, "Tags", id);
|
||||||
break;
|
break;
|
||||||
/* FIXME: Use to limit the tags to specific pads */
|
/* FIXME: Use to limit the tags to specific pads */
|
||||||
case GST_MATROSKA_ID_TARGETS:
|
|
||||||
ret = gst_ebml_read_skip (ebml);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
|
DEBUG_ELEMENT_STOP (common, ebml, "Tags", ret);
|
||||||
|
|
||||||
|
if (G_LIKELY (!gst_tag_list_is_empty (taglist)))
|
||||||
gst_matroska_read_common_found_global_tag (common, el, taglist);
|
gst_matroska_read_common_found_global_tag (common, el, taglist);
|
||||||
|
else
|
||||||
|
gst_tag_list_free (taglist);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,18 @@ typedef struct _GstMatroskaReadCommon {
|
||||||
/* state */
|
/* state */
|
||||||
GstMatroskaReadState state;
|
GstMatroskaReadState state;
|
||||||
|
|
||||||
|
|
||||||
/* did we parse cues/tracks/segmentinfo already? */
|
/* did we parse cues/tracks/segmentinfo already? */
|
||||||
gboolean index_parsed;
|
gboolean index_parsed;
|
||||||
gboolean segmentinfo_parsed;
|
gboolean segmentinfo_parsed;
|
||||||
gboolean attachments_parsed;
|
gboolean attachments_parsed;
|
||||||
|
gboolean chapters_parsed;
|
||||||
GList *tags_parsed;
|
GList *tags_parsed;
|
||||||
|
|
||||||
|
/* chapters stuff */
|
||||||
|
GstToc *toc;
|
||||||
|
gboolean toc_updated;
|
||||||
|
|
||||||
/* start-of-segment */
|
/* start-of-segment */
|
||||||
guint64 ebml_segment_start;
|
guint64 ebml_segment_start;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue