Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
gst-plugins-good
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
George Kiagiadakis
gst-plugins-good
Commits
113ba4ac
Commit
113ba4ac
authored
Mar 29, 2012
by
Alexander Saprykin
Committed by
Stefan Sauer
Apr 02, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
matroska: add GstToc support for muxer
parent
80f8a506
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
291 additions
and
15 deletions
+291
-15
gst/matroska/matroska-mux.c
gst/matroska/matroska-mux.c
+290
-14
gst/matroska/matroska-mux.h
gst/matroska/matroska-mux.h
+1
-1
No files found.
gst/matroska/matroska-mux.c
View file @
113ba4ac
...
...
@@ -56,6 +56,8 @@
#include "matroska-mux.h"
#include "matroska-ids.h"
#define GST_MATROSKA_MUX_CHAPLANG "und"
GST_DEBUG_CATEGORY_STATIC
(
matroskamux_debug
);
#define GST_CAT_DEFAULT matroskamux_debug
...
...
@@ -273,8 +275,10 @@ static void
gst_matroska_mux_add_interfaces
(
GType
type
)
{
static
const
GInterfaceInfo
tag_setter_info
=
{
NULL
,
NULL
,
NULL
};
static
const
GInterfaceInfo
toc_setter_info
=
{
NULL
,
NULL
,
NULL
};
g_type_add_interface_static
(
type
,
GST_TYPE_TAG_SETTER
,
&
tag_setter_info
);
g_type_add_interface_static
(
type
,
GST_TYPE_TOC_SETTER
,
&
toc_setter_info
);
}
static
void
...
...
@@ -673,6 +677,13 @@ gst_matroska_mux_reset (GstElement * element)
/* reset tags */
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
;
}
/**
...
...
@@ -806,6 +817,30 @@ gst_matroska_mux_handle_sink_event (GstCollectPads2 * pads,
event
=
NULL
;
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_NEWSEGMENT
:{
GstFormat
format
;
...
...
@@ -2329,6 +2364,110 @@ gst_matroska_mux_track_header (GstMatroskaMux * mux,
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:
...
...
@@ -2343,6 +2482,7 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
const
gchar
*
doctype
;
guint32
seekhead_id
[]
=
{
GST_MATROSKA_ID_SEGMENTINFO
,
GST_MATROSKA_ID_TRACKS
,
GST_MATROSKA_ID_CHAPTERS
,
GST_MATROSKA_ID_CUES
,
GST_MATROSKA_ID_TAGS
,
0
...
...
@@ -2503,6 +2643,68 @@ gst_matroska_mux_start (GstMatroskaMux * mux)
}
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 */
gst_ebml_write_flush_cache
(
ebml
,
FALSE
,
0
);
}
...
...
@@ -2566,6 +2768,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:
...
...
@@ -2619,22 +2859,45 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
/* tags */
tags
=
gst_tag_setter_get_tag_list
(
GST_TAG_SETTER
(
mux
));
if
(
tags
!=
NULL
&&
!
gst_tag_list_is_empty
(
tags
))
{
guint64
master_tags
,
master_tag
;
if
((
tags
!=
NULL
&&
!
gst_tag_list_is_empty
(
tags
))
||
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"
);
/* 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
);
gst_ebml_write_master_finish
(
ebml
,
master_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 */
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
);
if
(
tags
!=
NULL
)
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
);
}
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
);
}
/* update seekhead. We know that:
* - a seekhead contains
4
entries.
* - a seekhead contains
5
entries.
* - order of entries is as above.
* - a seekhead has a 4-byte header + 8-byte length
* - each entry is 2-byte master, 2-byte ID pointer,
...
...
@@ -2647,9 +2910,10 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
mux
->
info_pos
-
mux
->
segment_master
);
gst_ebml_replace_uint
(
ebml
,
mux
->
seekhead_pos
+
60
,
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
,
mux
->
c
ue
s_pos
-
mux
->
segment_master
);
mux
->
c
hapter
s_pos
-
mux
->
segment_master
);
}
else
{
/* void'ify */
guint64
my_pos
=
ebml
->
pos
;
...
...
@@ -2658,9 +2922,9 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
gst_ebml_write_buffer_header
(
ebml
,
GST_EBML_ID_VOID
,
26
);
gst_ebml_write_seek
(
ebml
,
my_pos
);
}
if
(
tags
!=
NULL
)
{
if
(
mux
->
index
!=
NULL
)
{
gst_ebml_replace_uint
(
ebml
,
mux
->
seekhead_pos
+
116
,
mux
->
tag
s_pos
-
mux
->
segment_master
);
mux
->
cue
s_pos
-
mux
->
segment_master
);
}
else
{
/* void'ify */
guint64
my_pos
=
ebml
->
pos
;
...
...
@@ -2670,6 +2934,18 @@ gst_matroska_mux_finish (GstMatroskaMux * mux)
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:
* - first get the overall duration
* (a released track may have left a duration in here)
...
...
gst/matroska/matroska-mux.h
View file @
113ba4ac
...
...
@@ -110,6 +110,7 @@ typedef struct _GstMatroskaMux {
guint64
segment_pos
,
seekhead_pos
,
cues_pos
,
chapters_pos
,
tags_pos
,
info_pos
,
tracks_pos
,
...
...
@@ -125,7 +126,6 @@ typedef struct _GstMatroskaMux {
/* GstForceKeyUnit event */
GstEvent
*
force_key_unit_event
;
}
GstMatroskaMux
;
typedef
struct
_GstMatroskaMuxClass
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment