mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-19 14:56:36 +00:00
Merge branch '0.10'
Conflicts: docs/gst/gstreamer-sections.txt gst/Makefile.am gst/gst.c gst/gst.h gst/gstevent.c gst/gstevent.h gst/gstmessage.h gst/gstquark.c gst/gstquark.h gst/gstquery.c gst/gstquery.h tests/check/Makefile.am
This commit is contained in:
commit
1074a4e99a
24 changed files with 2807 additions and 3 deletions
|
@ -42,6 +42,7 @@ EXTRA_DIST = \
|
|||
part-stream-status.txt \
|
||||
part-streams.txt \
|
||||
part-synchronisation.txt \
|
||||
part-toc.txt \
|
||||
part-TODO.txt \
|
||||
part-trickmodes.txt
|
||||
|
||||
|
|
89
docs/design/part-toc.txt
Normal file
89
docs/design/part-toc.txt
Normal file
|
@ -0,0 +1,89 @@
|
|||
Implementing GstToc support in GStreamer elements
|
||||
|
||||
1. General info about GstToc structure
|
||||
|
||||
GstToc introduces a general way to handle chapters within multimedia
|
||||
formats. GstToc can be represented as tree structure with arbitrary
|
||||
hierarchy. Tree item can be either of two types: chapter or edition.
|
||||
Chapter acts like a part of the media data, for example audio track
|
||||
in CUE sheet, or part of the movie. Edition acts like some kind of
|
||||
alternative way to process media content, for example DVD angles.
|
||||
GstToc has one limitation on tree structure: on the same level of
|
||||
hierarchy there couldn't be items of different type, i.e. you shouldn't
|
||||
have editions and chapters mixed together. Here is an example of right TOC:
|
||||
|
||||
------- TOC -------
|
||||
/ \
|
||||
edition1 edition2
|
||||
| |
|
||||
-chapter1 -chapter3
|
||||
-chapter2
|
||||
|
||||
Here are two editions, the first contains two chapters, and the second
|
||||
has only one chapter. And here is an example of invalid TOC:
|
||||
|
||||
------- TOC -------
|
||||
/ \
|
||||
edition1 chapter1
|
||||
|
|
||||
-chapter1
|
||||
-chapter2
|
||||
|
||||
Here you have edition1 and chapter1 mixed on the same level of hierarchy,
|
||||
and such TOC will be considered broken.
|
||||
|
||||
GstToc has 'entries' field of GList type which consists of children items.
|
||||
Each item is of type GstTocEntry. Also GstToc has list of tags and
|
||||
GstStructure called 'info'. Please, use GstToc.info and GstTocEntry.info
|
||||
fields this way: create a GstStructure, put all info related to your element
|
||||
there and put this structure into the 'info' field under the name of your
|
||||
element. Some fields in the 'info' structure can be used for internal
|
||||
purposes, so you should use it in the way described above to not to
|
||||
overwrite already existent fields.
|
||||
|
||||
Let's look at GstTocEntry a bit closer. One of the most important fields
|
||||
is 'uid', which must be unique for each item within the TOC. This is used
|
||||
to identify each item inside TOC, especially when element receives TOC
|
||||
select event with UID to seek on. Field 'subentries' of type GList contains
|
||||
children items of type GstTocEntry. Thus you can achieve arbitrary hierarchy
|
||||
level. Field 'type' can be either GST_TOC_ENTRY_TYPE_CHAPTER or
|
||||
GST_TOC_ENTRY_TYPE_EDITION which corresponds to chapter or edition type of
|
||||
item respectively. Field 'pads' of type GList contains list of GStreamer
|
||||
pads related to the item. It can be used for example to link a TOC with
|
||||
specific pad. Field 'tags' is a list of tags related to the item. And field
|
||||
'info' is similar to GstToc.info described above.
|
||||
|
||||
So, a little more about managing GstToc. Use gst_toc_new() and gst_toc_free()
|
||||
to create/free it. GstTocEntry can be created using gst_toc_entry_new() and
|
||||
gst_toc_entry_new_with_pad(). The latter method used to create GstTocEntry
|
||||
linked to particular pad. While building GstToc you can set start and stop
|
||||
timestamps for each item using gst_toc_entry_set_start_stop().
|
||||
The best way to process already created GstToc is to recursively go through
|
||||
the 'entries' and 'subentries' fields.
|
||||
|
||||
2. Working with GstQuery
|
||||
|
||||
GstQuery with GstToc can be created using gst_query_new_toc(). Use
|
||||
gst_query_set_toc() to set TOC into the query and parse it with
|
||||
gst_query_parse_toc(). The 'extend_uid' parameter (0 for root level) in two
|
||||
last methods should be used for TOC extending: get GstTocEntry with
|
||||
gst_toc_find_entry() by given UID and use it to add your own chapters/editions.
|
||||
The common action on such query is to set TOC for it.
|
||||
|
||||
3. Working with GstMessage
|
||||
|
||||
GstMessage with GstToc can be created using gst_message_new_toc() and parsed
|
||||
with gst_message_parse_toc(). The 'updated' parameter in these methods indicates
|
||||
whether the TOC was just discovered (set to false) or TOC was already found and
|
||||
have been updated (set to true). The common usage for such message is to post it
|
||||
to pipeline in case you have discovered TOC data within your element.
|
||||
|
||||
4. Working with GstEvent
|
||||
|
||||
GstToc supports select event through GstEvent infrastructure. The idea is the
|
||||
following: when you receive TOC select event, parse it with
|
||||
gst_event_parse_toc_select() and seek stream (if it is not streamable) for
|
||||
specified TOC UID (you can use gst_toc_find_entry() to find entry in TOC by UID).
|
||||
To create TOC select event use gst_event_new_toc_select(). The common action on
|
||||
such event is to seek to specified UID within your element.
|
||||
|
|
@ -101,6 +101,8 @@ Windows. It is released under the GNU Library General Public License
|
|||
<xi:include href="xml/gsttagsetter.xml" />
|
||||
<xi:include href="xml/gsttask.xml" />
|
||||
<xi:include href="xml/gsttaskpool.xml" />
|
||||
<xi:include href="xml/gsttoc.xml" />
|
||||
<xi:include href="xml/gsttocsetter.xml" />
|
||||
<xi:include href="xml/gsttypefind.xml" />
|
||||
<xi:include href="xml/gsttypefindfactory.xml" />
|
||||
<xi:include href="xml/gsturihandler.xml" />
|
||||
|
|
|
@ -1005,6 +1005,12 @@ gst_event_parse_stream_config_setup_data
|
|||
gst_event_add_stream_config_header
|
||||
gst_event_get_n_stream_config_headers
|
||||
gst_event_parse_nth_stream_config_header
|
||||
|
||||
gst_event_new_toc
|
||||
gst_event_parse_toc
|
||||
|
||||
gst_event_new_toc_select
|
||||
gst_event_parse_toc_select
|
||||
<SUBSECTION Standard>
|
||||
GstEventClass
|
||||
GST_EVENT
|
||||
|
@ -1413,6 +1419,8 @@ gst_message_set_qos_stats
|
|||
gst_message_parse_qos
|
||||
gst_message_parse_qos_values
|
||||
gst_message_parse_qos_stats
|
||||
gst_message_new_toc
|
||||
gst_message_parse_toc
|
||||
|
||||
GstStructureChangeType
|
||||
gst_message_new_structure_change
|
||||
|
@ -2225,6 +2233,9 @@ gst_query_has_scheduling_mode
|
|||
|
||||
gst_query_new_drain
|
||||
|
||||
gst_query_new_toc
|
||||
gst_query_parse_toc
|
||||
gst_query_set_toc
|
||||
<SUBSECTION Standard>
|
||||
GstQueryClass
|
||||
GST_QUERY
|
||||
|
@ -2673,6 +2684,51 @@ gst_task_state_get_type
|
|||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<FILE>gsttoc</FILE>
|
||||
<TITLE>GstToc</TITLE>
|
||||
GstToc
|
||||
GstTocEntry
|
||||
GstTocEntryType
|
||||
gst_toc_entry_new
|
||||
gst_toc_entry_new_with_pad
|
||||
gst_toc_entry_free
|
||||
gst_toc_new
|
||||
gst_toc_free
|
||||
gst_toc_entry_copy
|
||||
gst_toc_copy
|
||||
gst_toc_find_entry
|
||||
gst_toc_entry_get_start_stop
|
||||
gst_toc_entry_set_start_stop
|
||||
<SUBSECTION Standard>
|
||||
GST_TYPE_TOC_ENTRY_TYPE
|
||||
<SUBSECTION Private>
|
||||
gst_toc_entry_type_get_type
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<FILE>gsttocsetter</FILE>
|
||||
<TITLE>GstTocSetter</TITLE>
|
||||
GstTocSetter
|
||||
GstTocSetterIFace
|
||||
gst_toc_setter_get_toc
|
||||
gst_toc_setter_get_toc_copy
|
||||
gst_toc_setter_reset_toc
|
||||
gst_toc_setter_set_toc
|
||||
gst_toc_setter_get_toc_entry
|
||||
gst_toc_setter_get_toc_entry_copy
|
||||
gst_toc_setter_add_toc_entry
|
||||
<SUBSECTION Standard>
|
||||
GST_IS_TOC_SETTER
|
||||
GST_TOC_SETTER
|
||||
GST_TOC_SETTER_GET_IFACE
|
||||
GST_TYPE_TOC_SETTER
|
||||
<SUBSECTION Private>
|
||||
gst_toc_setter_get_type
|
||||
</SECTION>
|
||||
|
||||
|
||||
<SECTION>
|
||||
<FILE>gsttypefind</FILE>
|
||||
<TITLE>GstTypeFind</TITLE>
|
||||
|
|
|
@ -94,6 +94,8 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
|
|||
gsttagsetter.c \
|
||||
gsttask.c \
|
||||
gsttaskpool.c \
|
||||
gsttoc.c \
|
||||
gsttocsetter.c \
|
||||
$(GST_TRACE_SRC) \
|
||||
gsttypefind.c \
|
||||
gsttypefindfactory.c \
|
||||
|
@ -185,6 +187,8 @@ gst_headers = \
|
|||
gsttagsetter.h \
|
||||
gsttask.h \
|
||||
gsttaskpool.h \
|
||||
gsttoc.h \
|
||||
gsttocsetter.h \
|
||||
gsttypefind.h \
|
||||
gsttypefindfactory.h \
|
||||
gsturi.h \
|
||||
|
|
|
@ -741,6 +741,7 @@ init_post (GOptionContext * context, GOptionGroup * group, gpointer data,
|
|||
_priv_gst_value_initialize ();
|
||||
g_type_class_ref (gst_param_spec_fraction_get_type ());
|
||||
_priv_gst_tag_initialize ();
|
||||
_priv_gst_toc_initialize ();
|
||||
gst_parse_context_get_type ();
|
||||
|
||||
_priv_gst_plugin_initialize ();
|
||||
|
|
|
@ -74,6 +74,8 @@
|
|||
#include <gst/gsttagsetter.h>
|
||||
#include <gst/gsttask.h>
|
||||
#include <gst/gsttaskpool.h>
|
||||
#include <gst/gsttoc.h>
|
||||
#include <gst/gsttocsetter.h>
|
||||
#include <gst/gsttypefind.h>
|
||||
#include <gst/gsttypefindfactory.h>
|
||||
#include <gst/gsturi.h>
|
||||
|
|
|
@ -54,6 +54,9 @@ extern const char g_log_domain_gstreamer[];
|
|||
/* for GstElement */
|
||||
#include "gstelement.h"
|
||||
|
||||
/* for GstToc */
|
||||
#include "gsttoc.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/* used by gstparse.c and grammar.y */
|
||||
|
@ -110,6 +113,16 @@ void _priv_gst_sample_initialize (void);
|
|||
void _priv_gst_tag_initialize (void);
|
||||
void _priv_gst_value_initialize (void);
|
||||
void _priv_gst_debug_init (void);
|
||||
void _priv_gst_toc_initialize (void);
|
||||
|
||||
/* TOC functions */
|
||||
/* These functions are used to parse TOC messages, events and queries */
|
||||
GstToc* _gst_toc_from_structure (const GstStructure *toc);
|
||||
GstStructure* _gst_toc_to_structure (const GstToc *toc);
|
||||
gboolean _gst_toc_structure_get_updated (const GstStructure * toc);
|
||||
void _gst_toc_structure_set_updated (GstStructure * toc, gboolean updated);
|
||||
gchar* _gst_toc_structure_get_extend_uid (const GstStructure * toc);
|
||||
void _gst_toc_structure_set_extend_uid (GstStructure * toc, const gchar * extend_uid);
|
||||
|
||||
/* Private registry functions */
|
||||
gboolean _priv_gst_registry_remove_cache_plugins (GstRegistry *registry);
|
||||
|
|
111
gst/gstevent.c
111
gst/gstevent.c
|
@ -113,6 +113,7 @@ static GstEventQuarks event_quarks[] = {
|
|||
{GST_EVENT_STREAM_CONFIG, "stream-config", 0},
|
||||
{GST_EVENT_SEGMENT, "segment", 0},
|
||||
{GST_EVENT_TAG, "tag", 0},
|
||||
{GST_EVENT_TOC, "toc", 0},
|
||||
{GST_EVENT_BUFFERSIZE, "buffersize", 0},
|
||||
{GST_EVENT_SINK_MESSAGE, "sink-message", 0},
|
||||
{GST_EVENT_EOS, "eos", 0},
|
||||
|
@ -124,6 +125,7 @@ static GstEventQuarks event_quarks[] = {
|
|||
{GST_EVENT_LATENCY, "latency", 0},
|
||||
{GST_EVENT_STEP, "step", 0},
|
||||
{GST_EVENT_RECONFIGURE, "reconfigure", 0},
|
||||
{GST_EVENT_TOC_SELECT, "toc-select", 0},
|
||||
{GST_EVENT_CUSTOM_UPSTREAM, "custom-upstream", 0},
|
||||
{GST_EVENT_CUSTOM_DOWNSTREAM, "custom-downstream", 0},
|
||||
{GST_EVENT_CUSTOM_DOWNSTREAM_OOB, "custom-downstream-oob", 0},
|
||||
|
@ -1610,3 +1612,112 @@ gst_event_new_stream_start (void)
|
|||
{
|
||||
return gst_event_new_custom (GST_EVENT_STREAM_START, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_event_new_toc:
|
||||
* @toc: #GstToc structure.
|
||||
* @updated: whether @toc was updated or not.
|
||||
*
|
||||
* Generate a TOC event from the given @toc. The purpose of the TOC event is to
|
||||
* inform elements that some kind of the TOC was found.
|
||||
*
|
||||
* Returns: a new #GstEvent.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
GstEvent *
|
||||
gst_event_new_toc (GstToc * toc, gboolean updated)
|
||||
{
|
||||
GstStructure *toc_struct;
|
||||
|
||||
g_return_val_if_fail (toc != NULL, NULL);
|
||||
|
||||
GST_CAT_INFO (GST_CAT_EVENT, "creating toc event");
|
||||
|
||||
toc_struct = _gst_toc_to_structure (toc);
|
||||
|
||||
if (G_LIKELY (toc_struct != NULL)) {
|
||||
_gst_toc_structure_set_updated (toc_struct, updated);
|
||||
return gst_event_new_custom (GST_EVENT_TOC, toc_struct);
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_event_parse_toc:
|
||||
* @event: a TOC event.
|
||||
* @toc: (out): pointer to #GstToc structure.
|
||||
* @updated: (out): pointer to store TOC updated flag.
|
||||
*
|
||||
* Parse a TOC @event and store the results in the given @toc and @updated locations.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
void
|
||||
gst_event_parse_toc (GstEvent * event, GstToc ** toc, gboolean * updated)
|
||||
{
|
||||
const GstStructure *structure;
|
||||
|
||||
g_return_if_fail (event != NULL);
|
||||
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TOC);
|
||||
g_return_if_fail (toc != NULL);
|
||||
|
||||
structure = gst_event_get_structure (event);
|
||||
*toc = _gst_toc_from_structure (structure);
|
||||
|
||||
if (updated != NULL)
|
||||
*updated = _gst_toc_structure_get_updated (structure);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_event_new_toc_select:
|
||||
* @uid: UID in the TOC to start playback from.
|
||||
*
|
||||
* Generate a TOC select event with the given @uid. The purpose of the
|
||||
* TOC select event is to start playback based on the TOC's entry with the
|
||||
* given @uid.
|
||||
*
|
||||
* Returns: a new #GstEvent.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
GstEvent *
|
||||
gst_event_new_toc_select (const gchar * uid)
|
||||
{
|
||||
GstStructure *structure;
|
||||
|
||||
g_return_val_if_fail (uid != NULL, NULL);
|
||||
|
||||
GST_CAT_INFO (GST_CAT_EVENT, "creating toc select event for UID: %s", uid);
|
||||
|
||||
structure = gst_structure_id_new (GST_QUARK (EVENT_TOC_SELECT),
|
||||
GST_QUARK (UID), G_TYPE_STRING, uid, NULL);
|
||||
|
||||
return gst_event_new_custom (GST_EVENT_TOC_SELECT, structure);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_event_parse_toc_select:
|
||||
* @event: a TOC select event.
|
||||
* @uid: (out): storage for the selection UID.
|
||||
*
|
||||
* Parse a TOC select @event and store the results in the given @uid location.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
void
|
||||
gst_event_parse_toc_select (GstEvent * event, gchar ** uid)
|
||||
{
|
||||
const GstStructure *structure;
|
||||
const GValue *val;
|
||||
|
||||
g_return_if_fail (event != NULL);
|
||||
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_TOC_SELECT);
|
||||
|
||||
structure = gst_event_get_structure (event);
|
||||
val = gst_structure_id_get_value (structure, GST_QUARK (UID));
|
||||
|
||||
if (uid != NULL)
|
||||
*uid = g_strdup (g_value_get_string (val));
|
||||
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ typedef enum {
|
|||
* without a SEGMENT event.
|
||||
* @GST_EVENT_SEGMENT_DONE: (unimplemented) Marks the end of a segment playback.
|
||||
* @GST_EVENT_GAP: (unimplemented) Marks a gap in the datastream.
|
||||
* @GST_EVENT_TOC: An event which indicates that a new table of contents (TOC)
|
||||
* was found or updated. Since: 0.10.37
|
||||
* @GST_EVENT_QOS: A quality message. Used to indicate to upstream elements
|
||||
* that the downstream elements should adjust their processing
|
||||
* rate.
|
||||
|
@ -114,6 +116,8 @@ typedef enum {
|
|||
* execute the step operation. Since: 0.10.24
|
||||
* @GST_EVENT_RECONFIGURE: A request for upstream renegotiating caps and reconfiguring.
|
||||
* Since: 0.11.0
|
||||
* @GST_EVENT_TOC_SELECT: A request for a new playback position based on TOC
|
||||
* entry's UID. Since 0.10.37
|
||||
* @GST_EVENT_CUSTOM_UPSTREAM: Upstream custom event
|
||||
* @GST_EVENT_CUSTOM_DOWNSTREAM: Downstream custom event that travels in the
|
||||
* data flow.
|
||||
|
@ -148,6 +152,7 @@ typedef enum {
|
|||
GST_EVENT_BUFFERSIZE = GST_EVENT_MAKE_TYPE (90, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
|
||||
GST_EVENT_SINK_MESSAGE = GST_EVENT_MAKE_TYPE (100, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
|
||||
GST_EVENT_EOS = GST_EVENT_MAKE_TYPE (110, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
|
||||
GST_EVENT_TOC = GST_EVENT_MAKE_TYPE (120, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY) | FLAG(STICKY_MULTI)),
|
||||
|
||||
/* non-sticky downstream serialized */
|
||||
GST_EVENT_SEGMENT_DONE = GST_EVENT_MAKE_TYPE (150, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
|
||||
|
@ -160,6 +165,7 @@ typedef enum {
|
|||
GST_EVENT_LATENCY = GST_EVENT_MAKE_TYPE (220, FLAG(UPSTREAM)),
|
||||
GST_EVENT_STEP = GST_EVENT_MAKE_TYPE (230, FLAG(UPSTREAM)),
|
||||
GST_EVENT_RECONFIGURE = GST_EVENT_MAKE_TYPE (240, FLAG(UPSTREAM)),
|
||||
GST_EVENT_TOC_SELECT = GST_EVENT_MAKE_TYPE (250, FLAG(UPSTREAM)),
|
||||
|
||||
/* custom events start here */
|
||||
GST_EVENT_CUSTOM_UPSTREAM = GST_EVENT_MAKE_TYPE (270, FLAG(UPSTREAM)),
|
||||
|
@ -520,6 +526,11 @@ void gst_event_copy_segment (GstEvent *event, GstSegment *se
|
|||
GstEvent* gst_event_new_tag (GstTagList *taglist) G_GNUC_MALLOC;
|
||||
void gst_event_parse_tag (GstEvent *event, GstTagList **taglist);
|
||||
|
||||
/* TOC event */
|
||||
GstEvent* gst_event_new_toc (GstToc *toc, gboolean updated);
|
||||
void gst_event_parse_toc (GstEvent *event, GstToc **toc, gboolean *updated);
|
||||
|
||||
|
||||
/* buffer */
|
||||
GstEvent * gst_event_new_buffer_size (GstFormat format, gint64 minsize, gint64 maxsize,
|
||||
gboolean async) G_GNUC_MALLOC;
|
||||
|
@ -561,6 +572,10 @@ void gst_event_parse_step (GstEvent *event, GstFormat *for
|
|||
/* renegotiate event */
|
||||
GstEvent* gst_event_new_reconfigure (void) G_GNUC_MALLOC;
|
||||
|
||||
/* TOC select event */
|
||||
GstEvent* gst_event_new_toc_select (const gchar *uid) G_GNUC_MALLOC;
|
||||
void gst_event_parse_toc_select (GstEvent *event, gchar **uid);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_EVENT_H__ */
|
||||
|
|
|
@ -104,6 +104,7 @@ static GstMessageQuarks message_quarks[] = {
|
|||
{GST_MESSAGE_STEP_START, "step-start", 0},
|
||||
{GST_MESSAGE_QOS, "qos", 0},
|
||||
{GST_MESSAGE_PROGRESS, "progress", 0},
|
||||
{GST_MESSAGE_TOC, "toc", 0},
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -2171,3 +2172,61 @@ gst_message_parse_progress (GstMessage * message, GstProgressType * type,
|
|||
GST_QUARK (CODE), G_TYPE_STRING, code,
|
||||
GST_QUARK (TEXT), G_TYPE_STRING, text, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_message_new_toc:
|
||||
* @src: the object originating the message.
|
||||
* @toc: #GstToc structure for the message.
|
||||
* @updated: whether TOC was updated or not.
|
||||
*
|
||||
* Create a new TOC message. The message is posted by elements
|
||||
* that discovered or updated a TOC.
|
||||
*
|
||||
* Returns: a new TOC message.
|
||||
*
|
||||
* MT safe.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
GstMessage *
|
||||
gst_message_new_toc (GstObject * src, GstToc * toc, gboolean updated)
|
||||
{
|
||||
GstStructure *toc_struct;
|
||||
|
||||
g_return_val_if_fail (toc != NULL, NULL);
|
||||
|
||||
toc_struct = _gst_toc_to_structure (toc);
|
||||
|
||||
if (G_LIKELY (toc_struct != NULL)) {
|
||||
_gst_toc_structure_set_updated (toc_struct, updated);
|
||||
return gst_message_new_custom (GST_MESSAGE_TOC, src, toc_struct);
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_message_parse_toc:
|
||||
* @message: a valid #GstMessage of type GST_MESSAGE_TOC.
|
||||
* @toc: (out): return location for the TOC.
|
||||
* @updated: (out): return location for the updated flag.
|
||||
*
|
||||
* Extract the TOC from the #GstMessage. The TOC returned in the
|
||||
* output argument is a copy; the caller must free it with
|
||||
* gst_toc_free() when done.
|
||||
*
|
||||
* MT safe.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
void
|
||||
gst_message_parse_toc (GstMessage * message, GstToc ** toc, gboolean * updated)
|
||||
{
|
||||
g_return_if_fail (GST_IS_MESSAGE (message));
|
||||
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TOC);
|
||||
g_return_if_fail (toc != NULL);
|
||||
|
||||
*toc = _gst_toc_from_structure (message->structure);
|
||||
|
||||
if (updated != NULL)
|
||||
*updated = _gst_toc_structure_get_updated (message->structure);
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ typedef struct _GstMessage GstMessage;
|
|||
* @GST_MESSAGE_QOS: A buffer was dropped or an element changed its processing
|
||||
* strategy for Quality of Service reasons. Since: 0.10.29
|
||||
* @GST_MESSAGE_PROGRESS: A progress message. Since: 0.10.33
|
||||
* @GST_MESSAGE_TOC: A new table of contents (TOC) was found or previously found TOC
|
||||
* was updated. Since: 0.10.37
|
||||
* @GST_MESSAGE_ANY: mask for all of the above messages.
|
||||
*
|
||||
* The different message types that are available.
|
||||
|
@ -124,6 +126,7 @@ typedef enum
|
|||
GST_MESSAGE_STEP_START = (1 << 23),
|
||||
GST_MESSAGE_QOS = (1 << 24),
|
||||
GST_MESSAGE_PROGRESS = (1 << 25),
|
||||
GST_MESSAGE_TOC = (1 << 26),
|
||||
GST_MESSAGE_ANY = ~0
|
||||
} GstMessageType;
|
||||
|
||||
|
@ -133,6 +136,7 @@ typedef enum
|
|||
#include <gst/gsttaglist.h>
|
||||
#include <gst/gststructure.h>
|
||||
#include <gst/gstquery.h>
|
||||
#include <gst/gsttoc.h>
|
||||
|
||||
#define GST_TYPE_MESSAGE (gst_message_get_type())
|
||||
#define GST_IS_MESSAGE(obj) (GST_IS_MINI_OBJECT_TYPE (obj, GST_TYPE_MESSAGE))
|
||||
|
@ -545,6 +549,9 @@ GstMessage * gst_message_new_progress (GstObject * src, GstProgress
|
|||
void gst_message_parse_progress (GstMessage * message, GstProgressType * type, gchar ** code,
|
||||
gchar ** text);
|
||||
|
||||
/* TOC */
|
||||
GstMessage * gst_message_new_toc (GstObject *src, GstToc *toc, gboolean updated);
|
||||
void gst_message_parse_toc (GstMessage *message, GstToc **toc, gboolean *updated);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
@ -56,7 +56,8 @@ static const gchar *_quark_strings[] = {
|
|||
"GstEventReconfigure", "segment", "GstQueryScheduling", "pull-mode",
|
||||
"allocator", "GstEventFlushStop", "options", "GstQueryAcceptCaps",
|
||||
"result", "GstQueryCaps", "filter", "modes", "GstEventStreamConfig",
|
||||
"setup-data", "stream-headers", "GstEventGap", "GstQueryDrain", "params"
|
||||
"setup-data", "stream-headers", "GstEventGap", "GstQueryDrain", "params",
|
||||
"toc-select", "uid", "toc"
|
||||
};
|
||||
|
||||
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
|
||||
|
|
|
@ -164,7 +164,10 @@ typedef enum _GstQuarkId
|
|||
GST_QUARK_EVENT_GAP = 135,
|
||||
GST_QUARK_QUERY_DRAIN = 136,
|
||||
GST_QUARK_PARAMS = 137,
|
||||
GST_QUARK_MAX = 138
|
||||
GST_QUARK_EVENT_TOC_SELECT = 138,
|
||||
GST_QUARK_UID = 139,
|
||||
GST_QUARK_QUERY_TOC = 140,
|
||||
GST_QUARK_MAX = 141
|
||||
} GstQuarkId;
|
||||
|
||||
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
|
||||
|
|
|
@ -110,6 +110,7 @@ static GstQueryQuarks query_quarks[] = {
|
|||
{GST_QUERY_ACCEPT_CAPS, "accept-caps", 0},
|
||||
{GST_QUERY_CAPS, "caps", 0},
|
||||
{GST_QUERY_DRAIN, "drain", 0},
|
||||
{GST_QUERY_TOC, "toc", 0},
|
||||
|
||||
{0, NULL, 0}
|
||||
};
|
||||
|
@ -2320,3 +2321,88 @@ gst_query_new_drain (void)
|
|||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_query_new_toc:
|
||||
*
|
||||
* Constructs a new query TOC query object. Use gst_query_unref()
|
||||
* when done with it. A TOC query is used to query the full TOC with
|
||||
* the UID marker for TOC extending (to insert some new entries).
|
||||
*
|
||||
* Returns: A #GstQuery.
|
||||
*/
|
||||
GstQuery *
|
||||
gst_query_new_toc (void)
|
||||
{
|
||||
GstQuery *query;
|
||||
|
||||
query = gst_query_new (GST_QUERY_TOC, NULL);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_query_set_toc:
|
||||
* @query: a #GstQuery with query type GST_QUERY_TOC.
|
||||
* @toc: the GstToc to set.
|
||||
* @extend_uid: UID which can be used for TOC extending (may be NULL),
|
||||
* 0 means root TOC level.
|
||||
*
|
||||
* Answer a TOC query by setting appropriate #GstToc structure.
|
||||
*/
|
||||
void
|
||||
gst_query_set_toc (GstQuery * query, GstToc * toc, const gchar * extend_uid)
|
||||
{
|
||||
GstStructure *structure;
|
||||
|
||||
g_return_if_fail (query != NULL);
|
||||
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_TOC);
|
||||
g_return_if_fail (toc != NULL);
|
||||
|
||||
structure = _gst_toc_to_structure (toc);
|
||||
|
||||
g_return_if_fail (structure != NULL);
|
||||
|
||||
/* that shouldn't be happen in normal usage */
|
||||
if (query->structure != NULL)
|
||||
gst_structure_free (query->structure);
|
||||
|
||||
if (extend_uid != NULL)
|
||||
_gst_toc_structure_set_extend_uid (structure, extend_uid);
|
||||
|
||||
query->structure = structure;
|
||||
gst_structure_set_parent_refcount (query->structure,
|
||||
&(query->mini_object.refcount));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_query_parse_toc:
|
||||
* @query: a #GstQuery.
|
||||
* @toc: (out): the storage for the received TOC (may be NULL).
|
||||
* @extend_uid: (out): the storage for the received extend UID marker (may be NULL),
|
||||
* 0 means root TOC level.
|
||||
*
|
||||
* Parse a TOC query, writing the TOC into @toc as a newly
|
||||
* allocated #GstToc and extend UID into @extend_uid, if the respective parameters
|
||||
* are non-NULL. Use @extend_uid value to insert new entries into the TOC (@extend_uid will
|
||||
* act as root entry for newly inserted entries).
|
||||
* Free @toc with gst_toc_free() and @extend_uid with g_free() after usage.
|
||||
*/
|
||||
void
|
||||
gst_query_parse_toc (GstQuery * query, GstToc ** toc, gchar ** extend_uid)
|
||||
{
|
||||
const GstStructure *structure;
|
||||
|
||||
g_return_if_fail (query != NULL);
|
||||
g_return_if_fail (GST_QUERY_TYPE (query) == GST_QUERY_TOC);
|
||||
|
||||
structure = gst_query_get_structure (query);
|
||||
|
||||
g_return_if_fail (structure != NULL);
|
||||
|
||||
if (toc != NULL)
|
||||
*toc = _gst_toc_from_structure (structure);
|
||||
|
||||
if (extend_uid != NULL)
|
||||
*extend_uid = _gst_toc_structure_get_extend_uid (structure);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <gst/gststructure.h>
|
||||
#include <gst/gstformat.h>
|
||||
#include <gst/gstpad.h>
|
||||
#include <gst/gsttoc.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -101,6 +102,8 @@ typedef enum {
|
|||
* @GST_QUERY_ACCEPT_CAPS: the accept caps query
|
||||
* @GST_QUERY_CAPS: the caps query
|
||||
* @GST_QUERY_DRAIN: wait till all serialized data is consumed downstream
|
||||
* @GST_QUERY_TOC: query the full table of contents (TOC) with the marker
|
||||
* for an entry which can be used to extend received TOC. Since 0.10.37.
|
||||
*
|
||||
* Standard predefined Query types
|
||||
*/
|
||||
|
@ -124,7 +127,8 @@ typedef enum {
|
|||
GST_QUERY_SCHEDULING = GST_QUERY_MAKE_TYPE (150, FLAG(UPSTREAM)),
|
||||
GST_QUERY_ACCEPT_CAPS = GST_QUERY_MAKE_TYPE (160, FLAG(BOTH)),
|
||||
GST_QUERY_CAPS = GST_QUERY_MAKE_TYPE (170, FLAG(BOTH)),
|
||||
GST_QUERY_DRAIN = GST_QUERY_MAKE_TYPE (180, FLAG(DOWNSTREAM) | FLAG(SERIALIZED))
|
||||
GST_QUERY_DRAIN = GST_QUERY_MAKE_TYPE (180, FLAG(DOWNSTREAM) | FLAG(SERIALIZED)),
|
||||
GST_QUERY_TOC = GST_QUERY_MAKE_TYPE (190, FLAG(BOTH))
|
||||
} GstQueryType;
|
||||
#undef FLAG
|
||||
|
||||
|
@ -476,6 +480,11 @@ void gst_query_intersect_caps_result (GstQuery *query, GstCaps *fi
|
|||
/* drain query */
|
||||
GstQuery * gst_query_new_drain (void) G_GNUC_MALLOC;
|
||||
|
||||
/* TOC query */
|
||||
GstQuery * gst_query_new_toc (void);
|
||||
void gst_query_set_toc (GstQuery *query, GstToc *toc, const gchar *extend_uid);
|
||||
void gst_query_parse_toc (GstQuery *query, GstToc **toc, gchar **extend_uid);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_QUERY_H__ */
|
||||
|
|
1010
gst/gsttoc.c
Normal file
1010
gst/gsttoc.c
Normal file
File diff suppressed because it is too large
Load diff
111
gst/gsttoc.h
Normal file
111
gst/gsttoc.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* GStreamer
|
||||
* (c) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
|
||||
*
|
||||
* gsttoc.h: generic TOC API declaration
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_TOC_H__
|
||||
#define __GST_TOC_H__
|
||||
|
||||
#include <gst/gstconfig.h>
|
||||
#include <gst/gsttaglist.h>
|
||||
#include <gst/gstformat.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstTocEntry GstTocEntry;
|
||||
typedef struct _GstToc GstToc;
|
||||
|
||||
/**
|
||||
* GstTocEntryType:
|
||||
* @GST_TOC_ENTRY_TYPE_CHAPTER: a chapter type entry.
|
||||
* @GST_TOC_ENTRY_TYPE_EDITION: an edition entry (angle or alternative in other terms).
|
||||
*
|
||||
* The different types of TOC entry.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_TOC_ENTRY_TYPE_CHAPTER = 0,
|
||||
GST_TOC_ENTRY_TYPE_EDITION = 1
|
||||
} GstTocEntryType;
|
||||
|
||||
/**
|
||||
* GstTocEntry:
|
||||
* @uid: unique (for a whole TOC) id of the entry. This value should be persistent and
|
||||
* should not be changed while updating TOC. @uid should be handled as "opaque" value
|
||||
* without meaning (e.g. applications should not assume the /editionX/chapterY/chapter/Z structure,
|
||||
* other demuxers could do something else), it should help to track updates of certain entries.
|
||||
* @type: #GstTocEntryType of this entry.
|
||||
* @subentries: list of #GstTocEntry children.
|
||||
* @pads: list of #GstPad objects, related to this #GstTocEntry.
|
||||
* @tags: tags related to this entry.
|
||||
* @info: extra information related to this entry.
|
||||
*
|
||||
* Definition of TOC entry structure.
|
||||
*/
|
||||
struct _GstTocEntry {
|
||||
gchar *uid;
|
||||
GstTocEntryType type;
|
||||
GList *subentries;
|
||||
GList *pads;
|
||||
GstTagList *tags;
|
||||
GstStructure *info;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
/* FIXME: pad member should be GstPad type, but that's
|
||||
* impossible due to recursive includes */
|
||||
|
||||
/**
|
||||
* GstToc:
|
||||
* @entries: list of #GstTocEntry entries of the TOC.
|
||||
* @tags: tags related to the whole TOC.
|
||||
* @info: extra information related to the TOC.
|
||||
*
|
||||
* Definition of TOC structure.
|
||||
*/
|
||||
struct _GstToc {
|
||||
GList *entries;
|
||||
GstTagList *tags;
|
||||
GstStructure *info;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
/* functions to create new structures */
|
||||
GstToc * gst_toc_new (void);
|
||||
GstTocEntry * gst_toc_entry_new (GstTocEntryType type, const gchar *uid);
|
||||
GstTocEntry * gst_toc_entry_new_with_pad (GstTocEntryType type, const gchar *uid, gpointer pad);
|
||||
|
||||
/* functions to free structures */
|
||||
void gst_toc_entry_free (GstTocEntry *entry);
|
||||
void gst_toc_free (GstToc *toc);
|
||||
|
||||
GstTocEntry * gst_toc_find_entry (const GstToc *toc, const gchar *uid);
|
||||
GstTocEntry * gst_toc_entry_copy (const GstTocEntry *entry);
|
||||
GstToc * gst_toc_copy (const GstToc *toc);
|
||||
|
||||
void gst_toc_entry_set_start_stop (GstTocEntry *entry, gint64 start, gint64 stop);
|
||||
gboolean gst_toc_entry_get_start_stop (const GstTocEntry *entry, gint64 *start, gint64 *stop);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_TOC_H__ */
|
||||
|
362
gst/gsttocsetter.c
Normal file
362
gst/gsttocsetter.c
Normal file
|
@ -0,0 +1,362 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
|
||||
*
|
||||
* gsttocsetter.c: interface for TOC setting on elements
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gsttocsetter
|
||||
* @short_description: Element interface that allows setting and retrieval
|
||||
* of the TOC
|
||||
*
|
||||
* Element interface that allows setting of the TOC.
|
||||
*
|
||||
* Elements that support some kind of chapters or editions (or tracks like in
|
||||
* the FLAC cue sheet) will implement this interface.
|
||||
*
|
||||
* If you just want to retrieve the TOC in your application then all you
|
||||
* need to do is watch for TOC messages on your pipeline's bus (or you can
|
||||
* perform TOC query). This interface is only for setting TOC data, not for
|
||||
* extracting it. To set TOC from the application, find proper tocsetter element
|
||||
* and set TOC using gst_toc_setter_set_toc().
|
||||
*
|
||||
* Elements implementing the #GstTocSetter interface can extend existing TOC
|
||||
* by getting extend UID for that (you can use gst_toc_find_entry() to retrieve it)
|
||||
* with any TOC entries received from downstream.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gst_private.h"
|
||||
#include "gsttocsetter.h"
|
||||
#include <gobject/gvaluecollector.h>
|
||||
#include <string.h>
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_toc_interface_debug);
|
||||
#define GST_CAT_DEFAULT tag_toc_interface_debug
|
||||
|
||||
static GQuark gst_toc_key;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GstToc *toc;
|
||||
GStaticMutex lock;
|
||||
} GstTocData;
|
||||
|
||||
GType
|
||||
gst_toc_setter_get_type (void)
|
||||
{
|
||||
static volatile gsize toc_setter_type = 0;
|
||||
|
||||
if (g_once_init_enter (&toc_setter_type)) {
|
||||
GType _type;
|
||||
static const GTypeInfo toc_setter_info = {
|
||||
sizeof (GstTocSetterIFace), /* class_size */
|
||||
NULL, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
NULL,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
0,
|
||||
0,
|
||||
NULL
|
||||
};
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_toc_interface_debug, "GstTocInterface", 0,
|
||||
"interfaces for the TOC");
|
||||
|
||||
_type = g_type_register_static (G_TYPE_INTERFACE, "GstTocSetter",
|
||||
&toc_setter_info, 0);
|
||||
|
||||
g_type_interface_add_prerequisite (_type, GST_TYPE_ELEMENT);
|
||||
|
||||
gst_toc_key = g_quark_from_static_string ("GST_TOC_SETTER");
|
||||
g_once_init_leave (&toc_setter_type, _type);
|
||||
}
|
||||
|
||||
return toc_setter_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_toc_data_free (gpointer p)
|
||||
{
|
||||
GstTocData *data = (GstTocData *) p;
|
||||
|
||||
if (data->toc)
|
||||
gst_toc_free (data->toc);
|
||||
|
||||
g_static_mutex_free (&data->lock);
|
||||
|
||||
g_slice_free (GstTocData, data);
|
||||
}
|
||||
|
||||
static GstTocData *
|
||||
gst_toc_setter_get_data (GstTocSetter * setter)
|
||||
{
|
||||
GstTocData *data;
|
||||
|
||||
data = g_object_get_qdata (G_OBJECT (setter), gst_toc_key);
|
||||
if (!data) {
|
||||
static GStaticMutex create_mutex = G_STATIC_MUTEX_INIT;
|
||||
|
||||
/* make sure no other thread is creating a GstTocData at the same time */
|
||||
g_static_mutex_lock (&create_mutex);
|
||||
data = g_object_get_qdata (G_OBJECT (setter), gst_toc_key);
|
||||
if (!data) {
|
||||
data = g_slice_new (GstTocData);
|
||||
g_static_mutex_init (&data->lock);
|
||||
data->toc = NULL;
|
||||
g_object_set_qdata_full (G_OBJECT (setter), gst_toc_key, data,
|
||||
gst_toc_data_free);
|
||||
}
|
||||
g_static_mutex_unlock (&create_mutex);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_reset_toc:
|
||||
* @setter: a #GstTocSetter.
|
||||
*
|
||||
* Reset the internal TOC. Elements should call this from within the
|
||||
* state-change handler.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
void
|
||||
gst_toc_setter_reset_toc (GstTocSetter * setter)
|
||||
{
|
||||
GstTocData *data;
|
||||
|
||||
g_return_if_fail (GST_IS_TOC_SETTER (setter));
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
|
||||
g_static_mutex_lock (&data->lock);
|
||||
if (data->toc) {
|
||||
gst_toc_free (data->toc);
|
||||
data->toc = NULL;
|
||||
}
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_get_toc:
|
||||
* @setter: a #GstTocSetter.
|
||||
*
|
||||
* Return current TOC the setter uses. The TOC should not be
|
||||
* modified or freed.
|
||||
*
|
||||
* This function is not thread-safe. Use gst_toc_setter_get_toc_copy() instead.
|
||||
*
|
||||
* Returns: a current snapshot of the TOC used in the setter
|
||||
* or NULL if none is used.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
const GstToc *
|
||||
gst_toc_setter_get_toc (GstTocSetter * setter)
|
||||
{
|
||||
g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL);
|
||||
|
||||
return gst_toc_setter_get_data (setter)->toc;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_get_toc_copy:
|
||||
* @setter: a #GstTocSetter.
|
||||
*
|
||||
* Return current TOC the setter uses. The difference between this
|
||||
* function and gst_toc_setter_get_toc() is that this function returns deep
|
||||
* copy of the TOC, so you can modify it in any way. This function is thread-safe.
|
||||
* Free it when done with gst_toc_free().
|
||||
*
|
||||
* Returns: a copy of the current snapshot of the TOC used in the setter
|
||||
* or NULL if none is used.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
GstToc *
|
||||
gst_toc_setter_get_toc_copy (GstTocSetter * setter)
|
||||
{
|
||||
GstTocData *data;
|
||||
GstToc *ret = NULL;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL);
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
g_static_mutex_lock (&data->lock);
|
||||
|
||||
if (data->toc != NULL)
|
||||
ret = gst_toc_copy (data->toc);
|
||||
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_set_toc:
|
||||
* @setter: a #GstTocSetter.
|
||||
* @toc: a #GstToc to set.
|
||||
*
|
||||
* Set the given TOC on the setter. Previously setted TOC will be
|
||||
* freed before setting a new one.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
void
|
||||
gst_toc_setter_set_toc (GstTocSetter * setter, const GstToc * toc)
|
||||
{
|
||||
GstTocData *data;
|
||||
|
||||
g_return_if_fail (GST_IS_TOC_SETTER (setter));
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
|
||||
g_static_mutex_lock (&data->lock);
|
||||
if (data->toc)
|
||||
gst_toc_free (data->toc);
|
||||
|
||||
data->toc = gst_toc_copy (toc);
|
||||
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_get_toc_entry:
|
||||
* @setter: a #GstTocSetter.
|
||||
* @uid: UID to find entry with.
|
||||
*
|
||||
* Return #GstTocEntry (if any) with given @uid. Returned entry should
|
||||
* not be modified or freed.
|
||||
*
|
||||
* This function is not thread-safe. Use gst_toc_setter_get_toc_entry_copy() instead.
|
||||
*
|
||||
* Returns: a TOC entry with given @uid from the TOC in the setter
|
||||
* or NULL if none entry with such @uid was found.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
const GstTocEntry *
|
||||
gst_toc_setter_get_toc_entry (GstTocSetter * setter, const gchar * uid)
|
||||
{
|
||||
GstTocData *data;
|
||||
const GstTocEntry *ret;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL);
|
||||
g_return_val_if_fail (uid != NULL, NULL);
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
|
||||
g_static_mutex_lock (&data->lock);
|
||||
|
||||
ret = gst_toc_find_entry (data->toc, uid);
|
||||
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_get_toc_entry_copy:
|
||||
* @setter: a #GstTocSetter.
|
||||
* @uid: UID to find entry with.
|
||||
*
|
||||
* Return #GstTocEntry (if any) with given @uid. It perform a deep copying,
|
||||
* so you can modify returned value. Free it when done with gst_toc_entry_free().
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* Returns: a TOC entry with given @uid from the TOC in the setter
|
||||
* or NULL if none entry with such @uid was found.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
GstTocEntry *
|
||||
gst_toc_setter_get_toc_entry_copy (GstTocSetter * setter, const gchar * uid)
|
||||
{
|
||||
GstTocData *data;
|
||||
GstTocEntry *ret = NULL;
|
||||
const GstTocEntry *search;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TOC_SETTER (setter), NULL);
|
||||
g_return_val_if_fail (uid != NULL, NULL);
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
|
||||
g_static_mutex_lock (&data->lock);
|
||||
|
||||
search = gst_toc_find_entry (data->toc, uid);
|
||||
if (search != NULL)
|
||||
ret = gst_toc_entry_copy (search);
|
||||
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_toc_setter_add_toc_entry:
|
||||
* @setter: a #GstTocSetter.
|
||||
* @parent_uid: UID of the parent entry to append given @entry. Use 0 for the TOC root level.
|
||||
* @entry: #GstTocEntry to append.
|
||||
*
|
||||
* Try to find entry with given @parent_uid and append an @entry to that #GstTocEntry.
|
||||
*
|
||||
* Returns: TRUE if entry with @parent_uid was found, FALSE otherwise.
|
||||
*
|
||||
* Since: 0.10.37
|
||||
*/
|
||||
gboolean
|
||||
gst_toc_setter_add_toc_entry (GstTocSetter * setter, const gchar * parent_uid,
|
||||
const GstTocEntry * entry)
|
||||
{
|
||||
GstTocData *data;
|
||||
GstTocEntry *parent;
|
||||
GstTocEntry *copy_entry;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_TOC_SETTER (setter), FALSE);
|
||||
g_return_val_if_fail (parent_uid != NULL, FALSE);
|
||||
g_return_val_if_fail (entry != NULL, FALSE);
|
||||
|
||||
data = gst_toc_setter_get_data (setter);
|
||||
|
||||
g_static_mutex_lock (&data->lock);
|
||||
|
||||
copy_entry = gst_toc_entry_copy (entry);
|
||||
|
||||
if (g_strcmp0 (parent_uid, "0") == 0)
|
||||
data->toc->entries = g_list_append (data->toc->entries, copy_entry);
|
||||
else {
|
||||
parent = gst_toc_find_entry (data->toc, parent_uid);
|
||||
|
||||
if (parent != NULL) {
|
||||
parent->subentries = g_list_append (parent->subentries, copy_entry);
|
||||
ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_static_mutex_unlock (&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
67
gst/gsttocsetter.h
Normal file
67
gst/gsttocsetter.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
|
||||
*
|
||||
* gsttocsetter.h: Interfaces for TOC
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_TOC_SETTER_H__
|
||||
#define __GST_TOC_SETTER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
#define GST_TYPE_TOC_SETTER (gst_toc_setter_get_type ())
|
||||
#define GST_TOC_SETTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TOC_SETTER, GstTocSetter))
|
||||
#define GST_IS_TOC_SETTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TOC_SETTER))
|
||||
#define GST_TOC_SETTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GST_TYPE_TOC_SETTER, GstTocSetterIFace))
|
||||
/**
|
||||
* GstTocSetter:
|
||||
*
|
||||
* Opaque #GstTocSetter data structure.
|
||||
*/
|
||||
typedef struct _GstTocSetter GstTocSetter;
|
||||
typedef struct _GstTocSetterIFace GstTocSetterIFace;
|
||||
|
||||
/**
|
||||
* GstTocSetterIFace:
|
||||
* @g_iface: parent interface type.
|
||||
*
|
||||
* #GstTocSetterIFace interface.
|
||||
*/
|
||||
|
||||
struct _GstTocSetterIFace
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/* signals */
|
||||
|
||||
/* virtual table */
|
||||
};
|
||||
|
||||
GType gst_toc_setter_get_type (void);
|
||||
void gst_toc_setter_reset_toc (GstTocSetter *setter);
|
||||
const GstToc * gst_toc_setter_get_toc (GstTocSetter *setter);
|
||||
GstToc * gst_toc_setter_get_toc_copy (GstTocSetter *setter);
|
||||
void gst_toc_setter_set_toc (GstTocSetter *setter, const GstToc *toc);
|
||||
const GstTocEntry * gst_toc_setter_get_toc_entry (GstTocSetter *setter, const gchar *uid);
|
||||
GstTocEntry * gst_toc_setter_get_toc_entry_copy (GstTocSetter *setter, const gchar *uid);
|
||||
gboolean gst_toc_setter_add_toc_entry (GstTocSetter *setter, const gchar *parent_uid, const GstTocEntry *entry);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* __GST_TOC_SETTER_H__ */
|
||||
|
|
@ -126,6 +126,8 @@ check_PROGRAMS = \
|
|||
gst/gsttag \
|
||||
gst/gsttagsetter \
|
||||
gst/gsttask \
|
||||
gst/gsttoc \
|
||||
gst/gsttocsetter \
|
||||
gst/gstvalue \
|
||||
generic/states \
|
||||
$(PARSE_CHECKS) \
|
||||
|
|
338
tests/check/gst/gsttoc.c
Normal file
338
tests/check/gst/gsttoc.c
Normal file
|
@ -0,0 +1,338 @@
|
|||
/* GStreamer
|
||||
*
|
||||
* unit test for GstToc
|
||||
*
|
||||
* Copyright (C) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* ------- TOC -------
|
||||
* / \
|
||||
* edition1 edition2
|
||||
* | |
|
||||
* -chapter1 -chapter3
|
||||
* -chapter2 |
|
||||
* -subchapter1
|
||||
*/
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
|
||||
#define ENTRY_ED1 "/edition1"
|
||||
#define ENTRY_ED2 "/edition2"
|
||||
#define ENTRY_ED3 "test-edition"
|
||||
|
||||
#define ENTRY_CH1 "/edition1/chapter1"
|
||||
#define ENTRY_CH2 "/edition1/chapter2"
|
||||
#define ENTRY_CH3 "/edition2/chapter3"
|
||||
#define ENTRY_CH4 "/test-chapter"
|
||||
|
||||
#define ENTRY_SUB1 "/edition2/chapter3/subchapter1"
|
||||
|
||||
#define ENTRY_TAG "EntryTag"
|
||||
#define TOC_TAG "TocTag"
|
||||
|
||||
#define TEST_UID "129537542"
|
||||
#define INFO_NAME "info"
|
||||
#define INFO_FIELD "info-test"
|
||||
#define INFO_TEXT_EN "info-text-entry"
|
||||
#define INFO_TEXT_TOC "info-text-toc"
|
||||
|
||||
#define CHECK_TOC_ENTRY(entry_c,type_c,uid_c) \
|
||||
{ \
|
||||
gchar *tag_c; \
|
||||
const GValue *val; \
|
||||
\
|
||||
fail_unless_equals_string (entry_c->uid, uid_c); \
|
||||
fail_unless (entry_c->type == type_c); \
|
||||
fail_unless (entry_c->tags != NULL); \
|
||||
fail_unless (entry_c->pads == NULL); \
|
||||
\
|
||||
fail_unless (entry_c->info != NULL); \
|
||||
val = gst_structure_get_value (entry_c->info, INFO_FIELD); \
|
||||
fail_unless (val != NULL); \
|
||||
fail_unless_equals_string (g_value_get_string (val), INFO_TEXT_EN); \
|
||||
\
|
||||
fail_unless (gst_tag_list_get_string (entry_c->tags, \
|
||||
GST_TAG_TITLE, &tag_c)); \
|
||||
fail_unless_equals_string (tag_c, ENTRY_TAG); \
|
||||
}
|
||||
|
||||
#define CHECK_TOC(toc_t) \
|
||||
{ \
|
||||
GstTocEntry *entry_t, *subentry_t; \
|
||||
gchar *tag_t; \
|
||||
const GValue *val; \
|
||||
/* check TOC */ \
|
||||
fail_unless (g_list_length (toc_t->entries) == 2); \
|
||||
fail_unless (toc_t->tags != NULL); \
|
||||
fail_unless (gst_tag_list_get_string (toc_t->tags, \
|
||||
GST_TAG_TITLE, &tag_t)); \
|
||||
fail_unless_equals_string (tag_t, TOC_TAG); \
|
||||
\
|
||||
fail_unless (toc_t->info != NULL); \
|
||||
val = gst_structure_get_value (toc_t->info, INFO_FIELD); \
|
||||
fail_unless (val != NULL); \
|
||||
fail_unless_equals_string (g_value_get_string (val), INFO_TEXT_TOC); \
|
||||
\
|
||||
/* check edition1 */ \
|
||||
entry_t = g_list_nth_data (toc_t->entries, 0); \
|
||||
fail_if (entry_t == NULL); \
|
||||
fail_unless (g_list_length (entry_t->subentries) == 2); \
|
||||
CHECK_TOC_ENTRY (entry_t, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED1); \
|
||||
/* check chapter1 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH1); \
|
||||
/* check chapter2 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 1); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH2); \
|
||||
/* check edition2 */ \
|
||||
entry_t = g_list_nth_data (toc_t->entries, 1); \
|
||||
fail_if (entry_t == NULL); \
|
||||
fail_unless (g_list_length (entry_t->subentries) == 1); \
|
||||
CHECK_TOC_ENTRY (entry_t, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED2); \
|
||||
/* check chapter3 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 1); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH3); \
|
||||
/* check subchapter1 */ \
|
||||
subentry_t = g_list_nth_data (subentry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_SUB1); \
|
||||
}
|
||||
|
||||
GST_START_TEST (test_serializing)
|
||||
{
|
||||
GstToc *toc, *test_toc = NULL;
|
||||
GstTocEntry *ed, *ch, *subch;
|
||||
GstEvent *event;
|
||||
GstMessage *message;
|
||||
GstQuery *query;
|
||||
gboolean updated;
|
||||
gchar *uid;
|
||||
gint64 start = -1, stop = -1;
|
||||
|
||||
toc = gst_toc_new ();
|
||||
fail_if (toc == NULL);
|
||||
gst_tag_list_add (toc->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
TOC_TAG, NULL);
|
||||
toc->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_TOC,
|
||||
NULL);
|
||||
|
||||
/* create edition1 */
|
||||
ed = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED1);
|
||||
fail_if (ed == NULL);
|
||||
gst_tag_list_add (ed->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ed->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (ed, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED1);
|
||||
|
||||
/* append chapter1 to edition1 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH1);
|
||||
fail_if (ch == NULL);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (ch, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH1);
|
||||
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
fail_unless (g_list_length (ed->subentries) == 1);
|
||||
|
||||
/* append chapter2 to edition1 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH2);
|
||||
fail_if (ch == NULL);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (ch, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH2);
|
||||
|
||||
/* append edition1 to the TOC */
|
||||
toc->entries = g_list_append (toc->entries, ed);
|
||||
fail_unless (g_list_length (toc->entries) == 1);
|
||||
|
||||
/* test gst_toc_entry_find() */
|
||||
ed = NULL;
|
||||
ed = gst_toc_find_entry (toc, ENTRY_ED1);
|
||||
|
||||
fail_if (ed == NULL);
|
||||
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
fail_unless (g_list_length (ed->subentries) == 2);
|
||||
|
||||
/* test info GstStructure */
|
||||
gst_toc_entry_set_start_stop (ch, 100, 1000);
|
||||
fail_if (!gst_toc_entry_get_start_stop (ch, &start, &stop));
|
||||
fail_unless (start == 100);
|
||||
fail_unless (stop == 1000);
|
||||
|
||||
/* create edition2 */
|
||||
ed = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED2);
|
||||
fail_if (ed == NULL);
|
||||
gst_tag_list_add (ed->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ed->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (ed, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED2);
|
||||
|
||||
/* create chapter3 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH3);
|
||||
fail_if (ch == NULL);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (ch, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH3);
|
||||
|
||||
/* create subchapter1 */
|
||||
subch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_SUB1);
|
||||
fail_if (subch == NULL);
|
||||
gst_tag_list_add (subch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
subch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
CHECK_TOC_ENTRY (subch, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_SUB1);
|
||||
|
||||
/* append subchapter1 to chapter3 */
|
||||
ch->subentries = g_list_append (ch->subentries, subch);
|
||||
fail_unless (g_list_length (ch->subentries) == 1);
|
||||
|
||||
/* append chapter3 to edition2 */
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
fail_unless (g_list_length (ed->subentries) == 1);
|
||||
|
||||
/* finally append edition2 to the TOC */
|
||||
toc->entries = g_list_append (toc->entries, ed);
|
||||
fail_unless (g_list_length (toc->entries) == 2);
|
||||
|
||||
/* test gst_toc_copy() */
|
||||
test_toc = gst_toc_copy (toc);
|
||||
fail_if (test_toc == NULL);
|
||||
CHECK_TOC (test_toc);
|
||||
gst_toc_free (test_toc);
|
||||
test_toc = NULL;
|
||||
|
||||
/* check TOC event handling */
|
||||
event = gst_event_new_toc (toc, TRUE);
|
||||
fail_if (event == NULL);
|
||||
fail_if (event->structure == NULL);
|
||||
fail_unless (event->type == GST_EVENT_TOC);
|
||||
ASSERT_MINI_OBJECT_REFCOUNT (GST_MINI_OBJECT (event), "GstEvent", 1);
|
||||
|
||||
gst_event_parse_toc (event, &test_toc, &updated);
|
||||
fail_unless (updated == TRUE);
|
||||
fail_if (test_toc == NULL);
|
||||
CHECK_TOC (test_toc);
|
||||
gst_toc_free (test_toc);
|
||||
gst_event_unref (event);
|
||||
updated = FALSE;
|
||||
test_toc = NULL;
|
||||
|
||||
/* check TOC message handling */
|
||||
message = gst_message_new_toc (NULL, toc, TRUE);
|
||||
fail_if (message == NULL);
|
||||
fail_if (event->structure == NULL);
|
||||
fail_unless (message->type == GST_MESSAGE_TOC);
|
||||
ASSERT_MINI_OBJECT_REFCOUNT (GST_MINI_OBJECT (message), "GstMessage", 1);
|
||||
|
||||
gst_message_parse_toc (message, &test_toc, &updated);
|
||||
fail_unless (updated == TRUE);
|
||||
fail_if (test_toc == NULL);
|
||||
CHECK_TOC (test_toc);
|
||||
gst_toc_free (test_toc);
|
||||
gst_message_unref (message);
|
||||
test_toc = NULL;
|
||||
|
||||
/* check TOC select event handling */
|
||||
event = gst_event_new_toc_select (TEST_UID);
|
||||
fail_if (event == NULL);
|
||||
fail_if (event->structure == NULL);
|
||||
fail_unless (event->type == GST_EVENT_TOC_SELECT);
|
||||
ASSERT_MINI_OBJECT_REFCOUNT (GST_MINI_OBJECT (event), "GstEvent", 1);
|
||||
|
||||
gst_event_parse_toc_select (event, &uid);
|
||||
fail_unless_equals_string (uid, TEST_UID);
|
||||
gst_event_unref (event);
|
||||
g_free (uid);
|
||||
|
||||
/* check TOC query handling */
|
||||
query = gst_query_new_toc ();
|
||||
fail_if (query == NULL);
|
||||
gst_query_set_toc (query, toc, TEST_UID);
|
||||
fail_if (query->structure == NULL);
|
||||
fail_unless (query->type == GST_QUERY_TOC);
|
||||
ASSERT_MINI_OBJECT_REFCOUNT (GST_MINI_OBJECT (query), "GstQuery", 1);
|
||||
|
||||
gst_query_parse_toc (query, &test_toc, &uid);
|
||||
fail_unless_equals_string (uid, TEST_UID);
|
||||
fail_if (test_toc == NULL);
|
||||
CHECK_TOC (test_toc);
|
||||
gst_toc_free (test_toc);
|
||||
gst_query_unref (query);
|
||||
g_free (uid);
|
||||
|
||||
/* that's wrong code, we should fail */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH4);
|
||||
toc->entries = g_list_prepend (toc->entries, ch);
|
||||
ASSERT_CRITICAL (message = gst_message_new_toc (NULL, toc, TRUE));
|
||||
|
||||
/* and yet another one */
|
||||
toc->entries = g_list_remove (toc->entries, ch);
|
||||
gst_toc_entry_free (ch);
|
||||
ed = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED3);
|
||||
ch = (GstTocEntry *) (toc->entries->data);
|
||||
ch->subentries = g_list_prepend (ch->subentries, ed);
|
||||
ASSERT_WARNING (message = gst_message_new_toc (NULL, toc, TRUE));
|
||||
|
||||
gst_toc_free (toc);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
gst_toc_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("GstToc");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_serializing);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (gst_toc);
|
401
tests/check/gst/gsttocsetter.c
Normal file
401
tests/check/gst/gsttocsetter.c
Normal file
|
@ -0,0 +1,401 @@
|
|||
/* GStreamer GstTocSetter interface unit tests
|
||||
* Copyright (C) 2010, 2012 Alexander Saprykin <xelfium@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <gst/check/gstcheck.h>
|
||||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ENTRY_ED1 "/edition1"
|
||||
#define ENTRY_ED2 "/edition2"
|
||||
#define ENTRY_ED3 "test-edition"
|
||||
|
||||
#define ENTRY_CH1 "/edition1/chapter1"
|
||||
#define ENTRY_CH2 "/edition1/chapter2"
|
||||
#define ENTRY_CH3 "/edition2/chapter3"
|
||||
#define ENTRY_CH4 "/test-chapter"
|
||||
|
||||
#define ENTRY_SUB1 "/edition2/chapter3/subchapter1"
|
||||
|
||||
#define ENTRY_TAG "EntryTag"
|
||||
#define TOC_TAG "TocTag"
|
||||
#define INFO_NAME "info"
|
||||
#define INFO_FIELD "info-test"
|
||||
#define INFO_TEXT_EN "info-text-entry"
|
||||
#define INFO_TEXT_TOC "info-text-toc"
|
||||
|
||||
#define CHECK_TOC_ENTRY(entry_c,type_c,uid_c) \
|
||||
{ \
|
||||
gchar *tag_c; \
|
||||
const GValue *val; \
|
||||
\
|
||||
fail_unless_equals_string (entry_c->uid, uid_c); \
|
||||
fail_unless (entry_c->type == type_c); \
|
||||
fail_unless (entry_c->tags != NULL); \
|
||||
fail_unless (entry_c->pads == NULL); \
|
||||
\
|
||||
fail_unless (entry_c->info != NULL); \
|
||||
val = gst_structure_get_value (entry_c->info, INFO_FIELD); \
|
||||
fail_unless (val != NULL); \
|
||||
fail_unless_equals_string (g_value_get_string (val), INFO_TEXT_EN); \
|
||||
\
|
||||
fail_unless (gst_tag_list_get_string (entry_c->tags, \
|
||||
GST_TAG_TITLE, &tag_c)); \
|
||||
fail_unless_equals_string (tag_c, ENTRY_TAG); \
|
||||
}
|
||||
|
||||
#define CHECK_TOC(toc_t) \
|
||||
{ \
|
||||
GstTocEntry *entry_t, *subentry_t; \
|
||||
gchar *tag_t; \
|
||||
const GValue *val; \
|
||||
/* check TOC */ \
|
||||
fail_unless (g_list_length (toc_t->entries) == 2); \
|
||||
fail_unless (toc_t->tags != NULL); \
|
||||
fail_unless (gst_tag_list_get_string (toc_t->tags, \
|
||||
GST_TAG_TITLE, &tag_t)); \
|
||||
fail_unless_equals_string (tag_t, TOC_TAG); \
|
||||
\
|
||||
fail_unless (toc_t->info != NULL); \
|
||||
val = gst_structure_get_value (toc_t->info, INFO_FIELD); \
|
||||
fail_unless (val != NULL); \
|
||||
fail_unless_equals_string (g_value_get_string (val), INFO_TEXT_TOC); \
|
||||
\
|
||||
/* check edition1 */ \
|
||||
entry_t = g_list_nth_data (toc_t->entries, 0); \
|
||||
fail_if (entry_t == NULL); \
|
||||
fail_unless (g_list_length (entry_t->subentries) == 2); \
|
||||
CHECK_TOC_ENTRY (entry_t, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED1); \
|
||||
/* check chapter1 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH1); \
|
||||
/* check chapter2 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 1); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH2); \
|
||||
/* check edition2 */ \
|
||||
entry_t = g_list_nth_data (toc_t->entries, 1); \
|
||||
fail_if (entry_t == NULL); \
|
||||
fail_unless (g_list_length (entry_t->subentries) == 1); \
|
||||
CHECK_TOC_ENTRY (entry_t, GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED2); \
|
||||
/* check chapter3 */ \
|
||||
subentry_t = g_list_nth_data (entry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 1); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH3); \
|
||||
/* check subchapter1 */ \
|
||||
subentry_t = g_list_nth_data (subentry_t->subentries, 0); \
|
||||
fail_if (subentry_t == NULL); \
|
||||
fail_unless (g_list_length (subentry_t->subentries) == 0); \
|
||||
CHECK_TOC_ENTRY (subentry_t, GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_SUB1); \
|
||||
}
|
||||
|
||||
/* some minimal GstTocSetter object */
|
||||
#define GST_TYPE_DUMMY_ENC gst_dummy_enc_get_type()
|
||||
|
||||
typedef GstElement GstDummyEnc;
|
||||
typedef GstElementClass GstDummyEncClass;
|
||||
|
||||
static void gst_dummy_enc_add_interfaces (GType enc_type);
|
||||
|
||||
GType gst_dummy_enc_get_type (void);
|
||||
GST_BOILERPLATE_FULL (GstDummyEnc, gst_dummy_enc, GstElement,
|
||||
GST_TYPE_ELEMENT, gst_dummy_enc_add_interfaces);
|
||||
|
||||
static void
|
||||
gst_dummy_enc_add_interfaces (GType enc_type)
|
||||
{
|
||||
static const GInterfaceInfo toc_setter_info = { NULL, NULL, NULL };
|
||||
|
||||
g_type_add_interface_static (enc_type, GST_TYPE_TOC_SETTER, &toc_setter_info);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dummy_enc_base_init (gpointer g_class)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dummy_enc_class_init (GstDummyEncClass * klass)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gst_dummy_enc_init (GstDummyEnc * enc, GstDummyEncClass * klass)
|
||||
{
|
||||
}
|
||||
|
||||
static GstToc *
|
||||
create_toc (void)
|
||||
{
|
||||
GstToc *toc;
|
||||
GstTocEntry *ed, *ch, *subch;
|
||||
|
||||
toc = gst_toc_new ();
|
||||
gst_tag_list_add (toc->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
TOC_TAG, NULL);
|
||||
toc->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_TOC,
|
||||
NULL);
|
||||
|
||||
/* create edition1 */
|
||||
ed = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED1);
|
||||
gst_tag_list_add (ed->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ed->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
/* append chapter1 to edition1 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH1);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
|
||||
/* append chapter2 to edition1 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH2);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
|
||||
/* append edition1 to the TOC */
|
||||
toc->entries = g_list_append (toc->entries, ed);
|
||||
|
||||
/* create edition2 */
|
||||
ed = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_EDITION, ENTRY_ED2);
|
||||
gst_tag_list_add (ed->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ed->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
/* create chapter3 */
|
||||
ch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_CH3);
|
||||
gst_tag_list_add (ch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
ch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
/* create subchapter1 */
|
||||
subch = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_CHAPTER, ENTRY_SUB1);
|
||||
gst_tag_list_add (subch->tags, GST_TAG_MERGE_APPEND, GST_TAG_TITLE,
|
||||
ENTRY_TAG, NULL);
|
||||
subch->info =
|
||||
gst_structure_new (INFO_NAME, INFO_FIELD, G_TYPE_STRING, INFO_TEXT_EN,
|
||||
NULL);
|
||||
|
||||
/* append subchapter1 to chapter3 */
|
||||
ch->subentries = g_list_append (ch->subentries, subch);
|
||||
|
||||
/* append chapter3 to edition2 */
|
||||
ed->subentries = g_list_append (ed->subentries, ch);
|
||||
|
||||
/* finally append edition2 to the TOC */
|
||||
toc->entries = g_list_append (toc->entries, ed);
|
||||
|
||||
return toc;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_set)
|
||||
{
|
||||
GstToc *toc;
|
||||
GstTocEntry *entry, *ed;
|
||||
GstTocSetter *setter;
|
||||
GstElement *enc;
|
||||
|
||||
enc = g_object_new (GST_TYPE_DUMMY_ENC, NULL);
|
||||
fail_unless (enc != NULL);
|
||||
|
||||
setter = GST_TOC_SETTER (enc);
|
||||
|
||||
toc = create_toc ();
|
||||
fail_unless (toc != NULL);
|
||||
|
||||
gst_toc_setter_set_toc (setter, toc);
|
||||
|
||||
gst_toc_free (toc);
|
||||
toc = gst_toc_setter_get_toc_copy (setter);
|
||||
|
||||
CHECK_TOC (toc);
|
||||
|
||||
/* test entry adding into the root TOC */
|
||||
entry = g_list_last (toc->entries)->data;
|
||||
toc->entries = g_list_remove (toc->entries, entry);
|
||||
|
||||
gst_toc_setter_set_toc (setter, toc);
|
||||
gst_toc_setter_add_toc_entry (setter, "0", entry);
|
||||
|
||||
gst_toc_free (toc);
|
||||
toc = gst_toc_setter_get_toc_copy (setter);
|
||||
|
||||
CHECK_TOC (toc);
|
||||
|
||||
/* test entry adding into the arbitrary entry */
|
||||
entry = gst_toc_find_entry (toc, ENTRY_CH2);
|
||||
fail_if (entry == NULL);
|
||||
|
||||
ed = toc->entries->data;
|
||||
ed->subentries = g_list_remove (ed->subentries, entry);
|
||||
|
||||
gst_toc_setter_add_toc_entry (setter, ed->uid, entry);
|
||||
|
||||
CHECK_TOC (toc);
|
||||
|
||||
gst_toc_free (toc);
|
||||
gst_toc_setter_reset_toc (setter);
|
||||
toc = gst_toc_setter_get_toc_copy (setter);
|
||||
|
||||
fail_unless (toc == NULL);
|
||||
|
||||
g_object_unref (enc);
|
||||
}
|
||||
|
||||
GST_END_TEST static int spin_and_wait = 1;
|
||||
static int threads_running = 0;
|
||||
|
||||
#define THREADS_TEST_SECONDS 1.5
|
||||
|
||||
static gpointer
|
||||
test_threads_thread_func1 (gpointer data)
|
||||
{
|
||||
GstToc *toc;
|
||||
GstTocSetter *setter = GST_TOC_SETTER (data);
|
||||
GTimer *timer;
|
||||
|
||||
toc = create_toc ();
|
||||
timer = g_timer_new ();
|
||||
|
||||
g_atomic_int_inc (&threads_running);
|
||||
while (g_atomic_int_get (&spin_and_wait))
|
||||
g_usleep (0);
|
||||
|
||||
GST_INFO ("Go!");
|
||||
g_timer_start (timer);
|
||||
|
||||
while (g_timer_elapsed (timer, NULL) < THREADS_TEST_SECONDS)
|
||||
gst_toc_setter_set_toc (setter, toc);
|
||||
|
||||
gst_toc_free (toc);
|
||||
g_timer_destroy (timer);
|
||||
GST_INFO ("Done");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
test_threads_thread_func2 (gpointer data)
|
||||
{
|
||||
GstToc *toc;
|
||||
GstTocSetter *setter = GST_TOC_SETTER (data);
|
||||
GTimer *timer;
|
||||
|
||||
toc = create_toc ();
|
||||
timer = g_timer_new ();
|
||||
|
||||
g_atomic_int_inc (&threads_running);
|
||||
while (g_atomic_int_get (&spin_and_wait))
|
||||
g_usleep (0);
|
||||
|
||||
GST_INFO ("Go!");
|
||||
g_timer_start (timer);
|
||||
|
||||
while (g_timer_elapsed (timer, NULL) < THREADS_TEST_SECONDS)
|
||||
gst_toc_setter_set_toc (setter, toc);
|
||||
|
||||
gst_toc_free (toc);
|
||||
g_timer_destroy (timer);
|
||||
GST_INFO ("Done");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
test_threads_thread_func3 (gpointer data)
|
||||
{
|
||||
GstTocSetter *setter = GST_TOC_SETTER (data);
|
||||
GTimer *timer;
|
||||
|
||||
timer = g_timer_new ();
|
||||
|
||||
g_atomic_int_inc (&threads_running);
|
||||
while (g_atomic_int_get (&spin_and_wait))
|
||||
g_usleep (0);
|
||||
|
||||
GST_INFO ("Go!");
|
||||
g_timer_start (timer);
|
||||
|
||||
while (g_timer_elapsed (timer, NULL) < THREADS_TEST_SECONDS) {
|
||||
gst_toc_setter_reset_toc (setter);
|
||||
}
|
||||
|
||||
g_timer_destroy (timer);
|
||||
GST_INFO ("Done");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GST_START_TEST (test_threads)
|
||||
{
|
||||
GstTocSetter *setter;
|
||||
GThread *threads[3];
|
||||
|
||||
setter = GST_TOC_SETTER (g_object_new (GST_TYPE_DUMMY_ENC, NULL));
|
||||
|
||||
spin_and_wait = TRUE;
|
||||
threads[0] = g_thread_create (test_threads_thread_func1, setter, TRUE, NULL);
|
||||
threads[1] = g_thread_create (test_threads_thread_func2, setter, TRUE, NULL);
|
||||
threads[2] = g_thread_create (test_threads_thread_func3, setter, TRUE, NULL);
|
||||
|
||||
while (g_atomic_int_get (&threads_running) < 3)
|
||||
g_usleep (10);
|
||||
|
||||
g_atomic_int_set (&spin_and_wait, FALSE);
|
||||
|
||||
g_thread_join (threads[0]);
|
||||
g_thread_join (threads[1]);
|
||||
g_thread_join (threads[2]);
|
||||
|
||||
g_object_unref (G_OBJECT (setter));
|
||||
}
|
||||
|
||||
GST_END_TEST static Suite *
|
||||
gst_toc_setter_suite (void)
|
||||
{
|
||||
Suite *s = suite_create ("GstTocSetter");
|
||||
TCase *tc_chain = tcase_create ("general");
|
||||
|
||||
suite_add_tcase (s, tc_chain);
|
||||
tcase_add_test (tc_chain, test_set);
|
||||
tcase_add_test (tc_chain, test_threads);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
GST_CHECK_MAIN (gst_toc_setter);
|
|
@ -69,6 +69,7 @@ static GstElement *pipeline;
|
|||
static EventLoopResult caught_error = ELR_NO_ERROR;
|
||||
static gboolean quiet = FALSE;
|
||||
static gboolean tags = FALSE;
|
||||
static gboolean toc = FALSE;
|
||||
static gboolean messages = FALSE;
|
||||
static gboolean is_live = FALSE;
|
||||
static gboolean waiting_eos = FALSE;
|
||||
|
@ -437,6 +438,35 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_toc_entry (gpointer data, gpointer user_data)
|
||||
{
|
||||
GstTocEntry *entry = (GstTocEntry *) data;
|
||||
const guint max_indent = 40;
|
||||
const gchar spc[max_indent + 1] = " ";
|
||||
const gchar *entry_types[] = { "chapter", "edition" };
|
||||
guint indent = MIN (GPOINTER_TO_UINT (user_data), max_indent);
|
||||
gint64 start, stop;
|
||||
|
||||
gst_toc_entry_get_start_stop (entry, &start, &stop);
|
||||
|
||||
PRINT ("%s%s:", &spc[max_indent - indent], entry_types[entry->type]);
|
||||
if (GST_CLOCK_TIME_IS_VALID (start)) {
|
||||
PRINT (" start: %" GST_TIME_FORMAT, GST_TIME_ARGS (start));
|
||||
}
|
||||
if (GST_CLOCK_TIME_IS_VALID (stop)) {
|
||||
PRINT (" stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
|
||||
}
|
||||
PRINT ("\n");
|
||||
indent += 2;
|
||||
|
||||
/* TODO: print tags */
|
||||
|
||||
/* loop over sub-toc entries */
|
||||
g_list_foreach (entry->subentries, print_toc_entry,
|
||||
GUINT_TO_POINTER (indent));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FAULT_HANDLER
|
||||
/* we only use sighandler here because the registers are not important */
|
||||
static void
|
||||
|
@ -612,6 +642,28 @@ event_loop (GstElement * pipeline, gboolean blocking, GstState target_state)
|
|||
gst_tag_list_free (tag_list);
|
||||
}
|
||||
break;
|
||||
case GST_MESSAGE_TOC:
|
||||
if (toc) {
|
||||
GstToc *toc_msg;
|
||||
gboolean updated;
|
||||
|
||||
if (GST_IS_ELEMENT (GST_MESSAGE_SRC (message))) {
|
||||
PRINT (_("FOUND TOC : found by element \"%s\".\n"),
|
||||
GST_MESSAGE_SRC_NAME (message));
|
||||
} else if (GST_IS_OBJECT (GST_MESSAGE_SRC (message))) {
|
||||
PRINT (_("FOUND TOC : found by object \"%s\".\n"),
|
||||
GST_MESSAGE_SRC_NAME (message));
|
||||
} else {
|
||||
PRINT (_("FOUND TOC\n"));
|
||||
}
|
||||
|
||||
gst_message_parse_toc (message, &toc_msg, &updated);
|
||||
/* recursively loop over toc entries */
|
||||
g_list_foreach (toc_msg->entries, print_toc_entry,
|
||||
GUINT_TO_POINTER (0));
|
||||
gst_toc_free (toc_msg);
|
||||
}
|
||||
break;
|
||||
case GST_MESSAGE_INFO:{
|
||||
GError *gerror;
|
||||
gchar *debug;
|
||||
|
@ -832,6 +884,8 @@ main (int argc, char *argv[])
|
|||
GOptionEntry options[] = {
|
||||
{"tags", 't', 0, G_OPTION_ARG_NONE, &tags,
|
||||
N_("Output tags (also known as metadata)"), NULL},
|
||||
{"toc", 'c', 0, G_OPTION_ARG_NONE, &toc,
|
||||
N_("Ouput TOC (chapters and editions)"), NULL},
|
||||
{"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
|
||||
N_("Output status information and property notifications"), NULL},
|
||||
{"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
|
||||
|
|
Loading…
Reference in a new issue