mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-04-26 23:14:46 +00:00
ttml: Add plugin that supports TTML subtitles
Add a parser (ttmlparse) and renderer (ttmlrender) element that handle subtitles that use the EBU-TT-D profile of TTML1. https://bugzilla.gnome.org/show_bug.cgi?id=758232
This commit is contained in:
parent
280b4ac2ff
commit
d82ae6949f
17 changed files with 6338 additions and 2 deletions
12
configure.ac
12
configure.ac
|
@ -2456,6 +2456,16 @@ AG_GST_CHECK_FEATURE(DTLS, [DTLS plugin], dtls, [
|
|||
])
|
||||
])
|
||||
|
||||
dnl *** ttml ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_TTML, true)
|
||||
AG_GST_CHECK_FEATURE(TTML, [TTML plugin], ttml, [
|
||||
PKG_CHECK_MODULES(TTML, [ libxml-2.0 pango cairo pangocairo ], [
|
||||
HAVE_TTML="yes"
|
||||
], [
|
||||
HAVE_TTML="no"
|
||||
])
|
||||
])
|
||||
|
||||
dnl *** linsys ***
|
||||
translit(dnm, m, l) AM_CONDITIONAL(USE_LINSYS, true)
|
||||
AG_GST_CHECK_FEATURE(LINSYS, [Linear Systems SDI plugin], linsys, [
|
||||
|
@ -3529,6 +3539,7 @@ AM_CONDITIONAL(USE_OPENH264, false)
|
|||
AM_CONDITIONAL(USE_X265, false)
|
||||
AM_CONDITIONAL(USE_DTLS, false)
|
||||
AM_CONDITIONAL(USE_VULKAN, false)
|
||||
AM_CONDITIONAL(USE_TTML, false)
|
||||
|
||||
fi dnl of EXT plugins
|
||||
|
||||
|
@ -3841,6 +3852,7 @@ ext/xvid/Makefile
|
|||
ext/zbar/Makefile
|
||||
ext/dtls/Makefile
|
||||
ext/webrtcdsp/Makefile
|
||||
ext/ttml/Makefile
|
||||
po/Makefile.in
|
||||
docs/Makefile
|
||||
docs/plugins/Makefile
|
||||
|
|
|
@ -152,6 +152,8 @@
|
|||
<xi:include href="xml/element-wavescope.xml" />
|
||||
<xi:include href="xml/element-webrtcdsp.xml" />
|
||||
<xi:include href="xml/element-webrtcechoprobe.xml" />
|
||||
<xi:include href="xml/element-ttmlparse.xml" />
|
||||
<xi:include href="xml/element-ttmlrender.xml" />
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
|
@ -203,5 +205,6 @@
|
|||
<xi:include href="xml/plugin-voamrwbenc.xml" />
|
||||
<xi:include href="xml/plugin-webrtcdsp.xml" />
|
||||
<xi:include href="xml/plugin-zbar.xml" />
|
||||
<xi:include href="xml/plugin-ttmlsubs.xml" />
|
||||
</chapter>
|
||||
</book>
|
||||
|
|
|
@ -4805,3 +4805,22 @@ GST_TYPE_FFECTS_XRAY
|
|||
gst_ffects_xray_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-ttmlparse</FILE>
|
||||
<TITLE>ttmlparse</TITLE>
|
||||
GstTtmlParse
|
||||
<SUBSECTION Standard>
|
||||
GstTtmlParseClass
|
||||
GST_TYPE_TTML_PARSE
|
||||
gst_ttml_parse_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>element-ttmlrender</FILE>
|
||||
<TITLE>ttmlrender</TITLE>
|
||||
GstTtmlRender
|
||||
<SUBSECTION Standard>
|
||||
GstTtmlRenderClass
|
||||
GST_TYPE_TTML_RENDER
|
||||
gst_ttml_render_get_type
|
||||
</SECTION>
|
||||
|
|
61
docs/plugins/inspect/plugin-ttmlsubs.xml
Normal file
61
docs/plugins/inspect/plugin-ttmlsubs.xml
Normal file
|
@ -0,0 +1,61 @@
|
|||
<plugin>
|
||||
<name>ttmlsubs</name>
|
||||
<description>TTML subtitle handling</description>
|
||||
<filename>../../ext/ttml/.libs/libgstttmlsubs.so</filename>
|
||||
<basename>libgstttmlsubs.so</basename>
|
||||
<version>1.9.90</version>
|
||||
<license>LGPL</license>
|
||||
<source>gst-plugins-bad</source>
|
||||
<package>gst-ttml</package>
|
||||
<origin>http://www.bbc.co.uk/rd</origin>
|
||||
<elements>
|
||||
<element>
|
||||
<name>ttmlparse</name>
|
||||
<longname>TTML subtitle parser</longname>
|
||||
<class>Codec/Parser/Subtitle</class>
|
||||
<description>Parses TTML subtitle files</description>
|
||||
<author>GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>, Chris Bass <dash@rd.bbc.co.uk></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>application/ttml+xml</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>src</name>
|
||||
<direction>source</direction>
|
||||
<presence>always</presence>
|
||||
<details>text/x-raw(meta:GstSubtitleMeta)</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
<element>
|
||||
<name>ttmlrender</name>
|
||||
<longname>TTML subtitle renderer</longname>
|
||||
<class>Overlay/Subtitle</class>
|
||||
<description>Renders timed-text subtitles on top of video buffers</description>
|
||||
<author>David Schleef <ds@schleef.org>, Zeeshan Ali <zeeshan.ali@nokia.com>, Chris Bass <dash@rd.bbc.co.uk></author>
|
||||
<pads>
|
||||
<caps>
|
||||
<name>text_sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>text/x-raw(meta:GstSubtitleMeta)</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>video_sink</name>
|
||||
<direction>sink</direction>
|
||||
<presence>always</presence>
|
||||
<details>video/x-raw, format=(string){ BGRx, RGBx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, I420, YV12, AYUV, YUY2, UYVY, v308, Y41B, Y42B, Y444, NV12, NV21, A420, YUV9, YVU9, IYU1, GRAY8 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY), format=(string){ I420, YV12, YUY2, UYVY, AYUV, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, NV12, NV21, NV16, NV61, NV24, GRAY8, GRAY16_BE, GRAY16_LE, v308, IYU2, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, I422_10LE, I422_10BE, Y444_10LE, Y444_10BE, GBR, GBR_10LE, GBR_10BE, NV12_64Z32, A420_10LE, A420_10BE, A422_10LE, A422_10BE, A444_10LE, A444_10BE, P010_10LE, P010_10BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
|
||||
</caps>
|
||||
<caps>
|
||||
<name>src</name>
|
||||
<direction>source</direction>
|
||||
<presence>always</presence>
|
||||
<details>video/x-raw, format=(string){ BGRx, RGBx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, I420, YV12, AYUV, YUY2, UYVY, v308, Y41B, Y42B, Y444, NV12, NV21, A420, YUV9, YVU9, IYU1, GRAY8 }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]; video/x-raw(ANY), format=(string){ I420, YV12, YUY2, UYVY, AYUV, RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR, Y41B, Y42B, YVYU, Y444, v210, v216, NV12, NV21, NV16, NV61, NV24, GRAY8, GRAY16_BE, GRAY16_LE, v308, IYU2, RGB16, BGR16, RGB15, BGR15, UYVP, A420, RGB8P, YUV9, YVU9, IYU1, ARGB64, AYUV64, r210, I420_10LE, I420_10BE, I422_10LE, I422_10BE, Y444_10LE, Y444_10BE, GBR, GBR_10LE, GBR_10BE, NV12_64Z32, A420_10LE, A420_10BE, A422_10LE, A422_10BE, A444_10LE, A444_10BE, P010_10LE, P010_10BE }, width=(int)[ 1, 2147483647 ], height=(int)[ 1, 2147483647 ], framerate=(fraction)[ 0/1, 2147483647/1 ]</details>
|
||||
</caps>
|
||||
</pads>
|
||||
</element>
|
||||
</elements>
|
||||
</plugin>
|
|
@ -424,6 +424,12 @@ else
|
|||
WEBRTCDSP_DIR=
|
||||
endif
|
||||
|
||||
if USE_TTML
|
||||
TTML_DIR=ttml
|
||||
else
|
||||
TTML_DIR=
|
||||
endif
|
||||
|
||||
SUBDIRS=\
|
||||
$(VOAACENC_DIR) \
|
||||
$(ASSRENDER_DIR) \
|
||||
|
@ -495,7 +501,8 @@ SUBDIRS=\
|
|||
$(X265_DIR) \
|
||||
$(DTLS_DIR) \
|
||||
$(VULKAN_DIR) \
|
||||
$(WEBRTCDSP_DIR)
|
||||
$(WEBRTCDSP_DIR) \
|
||||
$(TTML_DIR)
|
||||
|
||||
DIST_SUBDIRS = \
|
||||
assrender \
|
||||
|
@ -565,6 +572,7 @@ DIST_SUBDIRS = \
|
|||
x265 \
|
||||
dtls \
|
||||
vulkan \
|
||||
webrtcdsp
|
||||
webrtcdsp \
|
||||
ttml
|
||||
|
||||
include $(top_srcdir)/common/parallel-subdirs.mak
|
||||
|
|
36
ext/ttml/Makefile.am
Normal file
36
ext/ttml/Makefile.am
Normal file
|
@ -0,0 +1,36 @@
|
|||
plugin_LTLIBRARIES = libgstttmlsubs.la
|
||||
|
||||
# sources used to compile this plug-in
|
||||
libgstttmlsubs_la_SOURCES = \
|
||||
subtitle.c \
|
||||
subtitlemeta.c \
|
||||
gstttmlparse.c \
|
||||
gstttmlparse.h \
|
||||
ttmlparse.c \
|
||||
ttmlparse.h \
|
||||
gstttmlrender.c \
|
||||
gstttmlplugin.c
|
||||
|
||||
# compiler and linker flags used to compile this plugin, set in configure.ac
|
||||
libgstttmlsubs_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BASE_CFLAGS) \
|
||||
$(GST_BASE_CFLAGS) \
|
||||
$(GST_CFLAGS) \
|
||||
$(TTML_CFLAGS)
|
||||
|
||||
libgstttmlsubs_la_LIBADD = \
|
||||
$(GST_BASE_LIBS) \
|
||||
$(GST_LIBS) \
|
||||
-lgstvideo-$(GST_API_VERSION) \
|
||||
$(TTML_LIBS)
|
||||
|
||||
libgstttmlsubs_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
libgstttmlsubs_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
|
||||
|
||||
# headers we need but don't want installed
|
||||
noinst_HEADERS = \
|
||||
subtitle.h \
|
||||
subtitlemeta.h \
|
||||
gstttmlparse.h \
|
||||
ttmlparse.h \
|
||||
gstttmlrender.h
|
570
ext/ttml/gstttmlparse.c
Normal file
570
ext/ttml/gstttmlparse.c
Normal file
|
@ -0,0 +1,570 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) 2004 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) <2015> British Broadcasting Corporation <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:element-ttmlparse
|
||||
*
|
||||
* Parses timed text subtitle files described using Timed Text Markup Language
|
||||
* (TTML). Currently, only the EBU-TT-D profile of TTML, designed for
|
||||
* distribution of subtitles over IP, is supported.
|
||||
*
|
||||
* The parser outputs a #GstBuffer for each scene in the input TTML file, a
|
||||
* scene being a period of time during which a static set of subtitles should
|
||||
* be visible. The parser places each text element within a scene into its own
|
||||
* #GstMemory within the scene's buffer, and attaches metadata to the buffer
|
||||
* describing the styling and layout associated with all the contained text
|
||||
* elements. A downstream renderer element uses this information to correctly
|
||||
* render the text on top of video frames.
|
||||
*
|
||||
* <refsect2>
|
||||
* <title>Example launch lines</title>
|
||||
* |[
|
||||
* gst-launch-1.0 filesrc location=<media file location> ! video/quicktime ! qtdemux name=q ttmlrender name=r q. ! queue ! h264parse ! avdec_h264 ! autovideoconvert ! r.video_sink filesrc location=<subtitle file location> blocksize=16777216 ! queue ! ttmlparse ! r.text_sink r. ! ximagesink q. ! queue ! aacparse ! avdec_aac ! audioconvert ! alsasink
|
||||
* ]| Parse and render TTML subtitles contained in a single XML file over an
|
||||
* MP4 stream containing H.264 video and AAC audio.
|
||||
* </refsect2>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "gstttmlparse.h"
|
||||
#include "ttmlparse.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (ttmlparse_debug);
|
||||
#define GST_CAT_DEFAULT ttmlparse_debug
|
||||
|
||||
#define DEFAULT_ENCODING NULL
|
||||
|
||||
static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
|
||||
GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("application/ttml+xml")
|
||||
);
|
||||
|
||||
static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS ("text/x-raw(meta:GstSubtitleMeta)")
|
||||
);
|
||||
|
||||
static gboolean gst_ttml_parse_src_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
static gboolean gst_ttml_parse_src_query (GstPad * pad, GstObject * parent,
|
||||
GstQuery * query);
|
||||
static gboolean gst_ttml_parse_sink_event (GstPad * pad, GstObject * parent,
|
||||
GstEvent * event);
|
||||
|
||||
static GstStateChangeReturn gst_ttml_parse_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static GstFlowReturn gst_ttml_parse_chain (GstPad * sinkpad, GstObject * parent,
|
||||
GstBuffer * buf);
|
||||
|
||||
#define gst_ttml_parse_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstTtmlParse, gst_ttml_parse, GST_TYPE_ELEMENT);
|
||||
|
||||
static void
|
||||
gst_ttml_parse_dispose (GObject * object)
|
||||
{
|
||||
GstTtmlParse *ttmlparse = GST_TTML_PARSE (object);
|
||||
|
||||
GST_DEBUG_OBJECT (ttmlparse, "cleaning up subtitle parser");
|
||||
|
||||
g_free (ttmlparse->encoding);
|
||||
ttmlparse->encoding = NULL;
|
||||
|
||||
g_free (ttmlparse->detected_encoding);
|
||||
ttmlparse->detected_encoding = NULL;
|
||||
|
||||
if (ttmlparse->adapter) {
|
||||
g_object_unref (ttmlparse->adapter);
|
||||
ttmlparse->adapter = NULL;
|
||||
}
|
||||
|
||||
if (ttmlparse->textbuf) {
|
||||
g_string_free (ttmlparse->textbuf, TRUE);
|
||||
ttmlparse->textbuf = NULL;
|
||||
}
|
||||
|
||||
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ttml_parse_class_init (GstTtmlParseClass * klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gst_ttml_parse_dispose;
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&sink_templ));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&src_templ));
|
||||
gst_element_class_set_static_metadata (element_class,
|
||||
"TTML subtitle parser", "Codec/Parser/Subtitle",
|
||||
"Parses TTML subtitle files",
|
||||
"GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>, "
|
||||
"Chris Bass <dash@rd.bbc.co.uk>");
|
||||
|
||||
element_class->change_state = gst_ttml_parse_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ttml_parse_init (GstTtmlParse * ttmlparse)
|
||||
{
|
||||
ttmlparse->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
|
||||
gst_pad_set_chain_function (ttmlparse->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ttml_parse_chain));
|
||||
gst_pad_set_event_function (ttmlparse->sinkpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ttml_parse_sink_event));
|
||||
gst_element_add_pad (GST_ELEMENT (ttmlparse), ttmlparse->sinkpad);
|
||||
|
||||
ttmlparse->srcpad = gst_pad_new_from_static_template (&src_templ, "src");
|
||||
gst_pad_set_event_function (ttmlparse->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ttml_parse_src_event));
|
||||
gst_pad_set_query_function (ttmlparse->srcpad,
|
||||
GST_DEBUG_FUNCPTR (gst_ttml_parse_src_query));
|
||||
gst_element_add_pad (GST_ELEMENT (ttmlparse), ttmlparse->srcpad);
|
||||
|
||||
ttmlparse->textbuf = g_string_new (NULL);
|
||||
gst_segment_init (&ttmlparse->segment, GST_FORMAT_TIME);
|
||||
ttmlparse->need_segment = TRUE;
|
||||
ttmlparse->encoding = g_strdup (DEFAULT_ENCODING);
|
||||
ttmlparse->detected_encoding = NULL;
|
||||
ttmlparse->adapter = gst_adapter_new ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Source pad functions.
|
||||
*/
|
||||
static gboolean
|
||||
gst_ttml_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
|
||||
{
|
||||
GstTtmlParse *self = GST_TTML_PARSE (parent);
|
||||
gboolean ret = FALSE;
|
||||
|
||||
GST_DEBUG ("Handling %s query", GST_QUERY_TYPE_NAME (query));
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_POSITION:{
|
||||
GstFormat fmt;
|
||||
|
||||
gst_query_parse_position (query, &fmt, NULL);
|
||||
if (fmt != GST_FORMAT_TIME) {
|
||||
ret = gst_pad_peer_query (self->sinkpad, query);
|
||||
} else {
|
||||
ret = TRUE;
|
||||
gst_query_set_position (query, GST_FORMAT_TIME, self->segment.position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_QUERY_SEEKING:
|
||||
{
|
||||
GstFormat fmt;
|
||||
gboolean seekable = FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
|
||||
if (fmt == GST_FORMAT_TIME) {
|
||||
GstQuery *peerquery = gst_query_new_seeking (GST_FORMAT_BYTES);
|
||||
|
||||
seekable = gst_pad_peer_query (self->sinkpad, peerquery);
|
||||
if (seekable)
|
||||
gst_query_parse_seeking (peerquery, NULL, &seekable, NULL, NULL);
|
||||
gst_query_unref (peerquery);
|
||||
}
|
||||
|
||||
gst_query_set_seeking (query, fmt, seekable, seekable ? 0 : -1, -1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = gst_pad_query_default (pad, parent, query);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_ttml_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
GstTtmlParse *self = GST_TTML_PARSE (parent);
|
||||
gboolean ret = FALSE;
|
||||
|
||||
GST_DEBUG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEEK:
|
||||
{
|
||||
GstFormat format;
|
||||
GstSeekFlags flags;
|
||||
GstSeekType start_type, stop_type;
|
||||
gint64 start, stop;
|
||||
gdouble rate;
|
||||
gboolean update;
|
||||
|
||||
gst_event_parse_seek (event, &rate, &format, &flags,
|
||||
&start_type, &start, &stop_type, &stop);
|
||||
|
||||
if (format != GST_FORMAT_TIME) {
|
||||
GST_WARNING_OBJECT (self, "we only support seeking in TIME format");
|
||||
gst_event_unref (event);
|
||||
goto beach;
|
||||
}
|
||||
|
||||
/* Convert that seek to a seeking in bytes at position 0,
|
||||
FIXME: could use an index */
|
||||
ret = gst_pad_push_event (self->sinkpad,
|
||||
gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
|
||||
GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, 0));
|
||||
|
||||
if (ret) {
|
||||
/* Apply the seek to our segment */
|
||||
gst_segment_do_seek (&self->segment, rate, format, flags,
|
||||
start_type, start, stop_type, stop, &update);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "segment after seek: %" GST_SEGMENT_FORMAT,
|
||||
&self->segment);
|
||||
|
||||
self->need_segment = TRUE;
|
||||
} else {
|
||||
GST_WARNING_OBJECT (self, "seek to 0 bytes failed");
|
||||
}
|
||||
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = gst_pad_event_default (pad, parent, event);
|
||||
break;
|
||||
}
|
||||
|
||||
beach:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
gst_convert_to_utf8 (const gchar * str, gsize len, const gchar * encoding,
|
||||
gsize * consumed, GError ** err)
|
||||
{
|
||||
gchar *ret = NULL;
|
||||
|
||||
*consumed = 0;
|
||||
/* The char cast is necessary in glib < 2.24 */
|
||||
ret =
|
||||
g_convert_with_fallback (str, len, "UTF-8", encoding, (char *) "*",
|
||||
consumed, NULL, err);
|
||||
if (ret == NULL)
|
||||
return ret;
|
||||
|
||||
/* + 3 to skip UTF-8 BOM if it was added */
|
||||
len = strlen (ret);
|
||||
if (len >= 3 && (guint8) ret[0] == 0xEF && (guint8) ret[1] == 0xBB
|
||||
&& (guint8) ret[2] == 0xBF)
|
||||
memmove (ret, ret + 3, len + 1 - 3);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
detect_encoding (const gchar * str, gsize len)
|
||||
{
|
||||
if (len >= 3 && (guint8) str[0] == 0xEF && (guint8) str[1] == 0xBB
|
||||
&& (guint8) str[2] == 0xBF)
|
||||
return g_strdup ("UTF-8");
|
||||
|
||||
if (len >= 2 && (guint8) str[0] == 0xFE && (guint8) str[1] == 0xFF)
|
||||
return g_strdup ("UTF-16BE");
|
||||
|
||||
if (len >= 2 && (guint8) str[0] == 0xFF && (guint8) str[1] == 0xFE)
|
||||
return g_strdup ("UTF-16LE");
|
||||
|
||||
if (len >= 4 && (guint8) str[0] == 0x00 && (guint8) str[1] == 0x00
|
||||
&& (guint8) str[2] == 0xFE && (guint8) str[3] == 0xFF)
|
||||
return g_strdup ("UTF-32BE");
|
||||
|
||||
if (len >= 4 && (guint8) str[0] == 0xFF && (guint8) str[1] == 0xFE
|
||||
&& (guint8) str[2] == 0x00 && (guint8) str[3] == 0x00)
|
||||
return g_strdup ("UTF-32LE");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
convert_encoding (GstTtmlParse * self, const gchar * str, gsize len,
|
||||
gsize * consumed)
|
||||
{
|
||||
const gchar *encoding;
|
||||
GError *err = NULL;
|
||||
gchar *ret = NULL;
|
||||
|
||||
*consumed = 0;
|
||||
|
||||
/* First try any detected encoding */
|
||||
if (self->detected_encoding) {
|
||||
ret =
|
||||
gst_convert_to_utf8 (str, len, self->detected_encoding, consumed, &err);
|
||||
|
||||
if (!err)
|
||||
return ret;
|
||||
|
||||
GST_WARNING_OBJECT (self, "could not convert string from '%s' to UTF-8: %s",
|
||||
self->detected_encoding, err->message);
|
||||
g_free (self->detected_encoding);
|
||||
self->detected_encoding = NULL;
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
/* Otherwise check if it's UTF8 */
|
||||
if (self->valid_utf8) {
|
||||
if (g_utf8_validate (str, len, NULL)) {
|
||||
GST_LOG_OBJECT (self, "valid UTF-8, no conversion needed");
|
||||
*consumed = len;
|
||||
return g_strndup (str, len);
|
||||
}
|
||||
GST_INFO_OBJECT (self, "invalid UTF-8!");
|
||||
self->valid_utf8 = FALSE;
|
||||
}
|
||||
|
||||
/* Else try fallback */
|
||||
encoding = self->encoding;
|
||||
if (encoding == NULL || *encoding == '\0') {
|
||||
/* if local encoding is UTF-8 and no encoding specified
|
||||
* via the environment variable, assume ISO-8859-15 */
|
||||
if (g_get_charset (&encoding)) {
|
||||
encoding = "ISO-8859-15";
|
||||
}
|
||||
}
|
||||
|
||||
ret = gst_convert_to_utf8 (str, len, encoding, consumed, &err);
|
||||
|
||||
if (err) {
|
||||
GST_WARNING_OBJECT (self, "could not convert string from '%s' to UTF-8: %s",
|
||||
encoding, err->message);
|
||||
g_error_free (err);
|
||||
|
||||
/* invalid input encoding, fall back to ISO-8859-15 (always succeeds) */
|
||||
ret = gst_convert_to_utf8 (str, len, "ISO-8859-15", consumed, NULL);
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"successfully converted %" G_GSIZE_FORMAT " characters from %s to UTF-8"
|
||||
"%s", len, encoding, (err) ? " , using ISO-8859-15 as fallback" : "");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
gst_ttml_parse_get_src_caps (GstTtmlParse * self)
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstCapsFeatures *features = gst_caps_features_new ("meta:GstSubtitleMeta",
|
||||
NULL);
|
||||
|
||||
caps = gst_caps_new_empty_simple ("text/x-raw");
|
||||
gst_caps_set_features (caps, 0, features);
|
||||
return caps;
|
||||
}
|
||||
|
||||
static void
|
||||
feed_textbuf (GstTtmlParse * self, GstBuffer * buf)
|
||||
{
|
||||
gboolean discont;
|
||||
gsize consumed;
|
||||
gchar *input = NULL;
|
||||
const guint8 *data;
|
||||
gsize avail;
|
||||
|
||||
discont = GST_BUFFER_IS_DISCONT (buf);
|
||||
|
||||
if (GST_BUFFER_OFFSET_IS_VALID (buf) &&
|
||||
GST_BUFFER_OFFSET (buf) != self->offset) {
|
||||
self->offset = GST_BUFFER_OFFSET (buf);
|
||||
discont = TRUE;
|
||||
}
|
||||
|
||||
if (discont) {
|
||||
GST_INFO ("discontinuity");
|
||||
/* flush the parser state */
|
||||
g_string_truncate (self->textbuf, 0);
|
||||
gst_adapter_clear (self->adapter);
|
||||
/* we could set a flag to make sure that the next buffer we push out also
|
||||
* has the DISCONT flag set, but there's no point really given that it's
|
||||
* subtitles which are discontinuous by nature. */
|
||||
}
|
||||
|
||||
self->offset += gst_buffer_get_size (buf);
|
||||
|
||||
gst_adapter_push (self->adapter, buf);
|
||||
|
||||
avail = gst_adapter_available (self->adapter);
|
||||
data = gst_adapter_map (self->adapter, avail);
|
||||
input = convert_encoding (self, (const gchar *) data, avail, &consumed);
|
||||
|
||||
if (input && consumed > 0) {
|
||||
if (self->textbuf) {
|
||||
g_string_free (self->textbuf, TRUE);
|
||||
self->textbuf = NULL;
|
||||
}
|
||||
self->textbuf = g_string_new (input);
|
||||
gst_adapter_unmap (self->adapter);
|
||||
gst_adapter_flush (self->adapter, consumed);
|
||||
} else {
|
||||
gst_adapter_unmap (self->adapter);
|
||||
}
|
||||
|
||||
g_free (input);
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
handle_buffer (GstTtmlParse * self, GstBuffer * buf)
|
||||
{
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
GstCaps *caps = NULL;
|
||||
GList *subtitle_list, *subtitle;
|
||||
GstClockTime begin = GST_BUFFER_PTS (buf);
|
||||
GstClockTime duration = GST_BUFFER_DURATION (buf);
|
||||
|
||||
if (self->first_buffer) {
|
||||
GstMapInfo map;
|
||||
|
||||
gst_buffer_map (buf, &map, GST_MAP_READ);
|
||||
self->detected_encoding = detect_encoding ((gchar *) map.data, map.size);
|
||||
gst_buffer_unmap (buf, &map);
|
||||
self->first_buffer = FALSE;
|
||||
}
|
||||
|
||||
feed_textbuf (self, buf);
|
||||
|
||||
if (!(caps = gst_ttml_parse_get_src_caps (self)))
|
||||
return GST_FLOW_EOS;
|
||||
|
||||
/* Push newsegment if needed */
|
||||
if (self->need_segment) {
|
||||
GST_LOG_OBJECT (self, "pushing newsegment event with %" GST_SEGMENT_FORMAT,
|
||||
&self->segment);
|
||||
|
||||
gst_pad_push_event (self->srcpad, gst_event_new_segment (&self->segment));
|
||||
self->need_segment = FALSE;
|
||||
}
|
||||
|
||||
subtitle_list = ttml_parse (self->textbuf->str, begin, duration);
|
||||
|
||||
for (subtitle = subtitle_list; subtitle; subtitle = subtitle->next) {
|
||||
GstBuffer *op_buffer = subtitle->data;
|
||||
self->segment.position = GST_BUFFER_PTS (op_buffer);
|
||||
|
||||
ret = gst_pad_push (self->srcpad, op_buffer);
|
||||
|
||||
if (ret != GST_FLOW_OK)
|
||||
GST_DEBUG_OBJECT (self, "flow: %s", gst_flow_get_name (ret));
|
||||
}
|
||||
|
||||
g_list_free (subtitle_list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_ttml_parse_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * buf)
|
||||
{
|
||||
GstTtmlParse *self = GST_TTML_PARSE (parent);
|
||||
return handle_buffer (self, buf);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_ttml_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
|
||||
{
|
||||
GstTtmlParse *self = GST_TTML_PARSE (parent);
|
||||
gboolean ret = FALSE;
|
||||
|
||||
GST_DEBUG ("Handling %s event", GST_EVENT_TYPE_NAME (event));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_SEGMENT:
|
||||
{
|
||||
const GstSegment *s;
|
||||
gst_event_parse_segment (event, &s);
|
||||
if (s->format == GST_FORMAT_TIME)
|
||||
gst_event_copy_segment (event, &self->segment);
|
||||
GST_DEBUG_OBJECT (self, "newsegment (%s)",
|
||||
gst_format_get_name (self->segment.format));
|
||||
|
||||
/* if not time format, we'll either start with a 0 timestamp anyway or
|
||||
* it's following a seek in which case we'll have saved the requested
|
||||
* seek segment and don't want to overwrite it (remember that on a seek
|
||||
* we always just seek back to the start in BYTES format and just throw
|
||||
* away all text that's before the requested position; if the subtitles
|
||||
* come from an upstream demuxer, it won't be able to handle our BYTES
|
||||
* seek request and instead send us a newsegment from the seek request
|
||||
* it received via its video pads instead, so all is fine then too) */
|
||||
ret = TRUE;
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = gst_pad_event_default (pad, parent, event);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_ttml_parse_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
||||
GstTtmlParse *self = GST_TTML_PARSE (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
/* format detection will init the parser state */
|
||||
self->offset = 0;
|
||||
self->valid_utf8 = TRUE;
|
||||
self->first_buffer = TRUE;
|
||||
g_free (self->detected_encoding);
|
||||
self->detected_encoding = NULL;
|
||||
g_string_truncate (self->textbuf, 0);
|
||||
gst_adapter_clear (self->adapter);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
if (ret == GST_STATE_CHANGE_FAILURE)
|
||||
return ret;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
76
ext/ttml/gstttmlparse.h
Normal file
76
ext/ttml/gstttmlparse.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2002> David A. Schleef <ds@schleef.org>
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_TTML_PARSE_H__
|
||||
#define __GST_TTML_PARSE_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstadapter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_TTML_PARSE \
|
||||
(gst_ttml_parse_get_type ())
|
||||
#define GST_TTML_PARSE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TTML_PARSE, GstTtmlParse))
|
||||
#define GST_TTML_PARSE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TTML_PARSE, GstTtmlParseClass))
|
||||
#define GST_IS_TTML_PARSE(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TTML_PARSE))
|
||||
#define GST_IS_TTML_PARSE_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TTML_PARSE))
|
||||
|
||||
typedef struct _GstTtmlParse GstTtmlParse;
|
||||
typedef struct _GstTtmlParseClass GstTtmlParseClass;
|
||||
|
||||
struct _GstTtmlParse {
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad, *srcpad;
|
||||
|
||||
/* contains the input in the input encoding */
|
||||
GstAdapter *adapter;
|
||||
/* contains the UTF-8 decoded input */
|
||||
GString *textbuf;
|
||||
|
||||
/* seek */
|
||||
guint64 offset;
|
||||
|
||||
/* Segment */
|
||||
GstSegment segment;
|
||||
gboolean need_segment;
|
||||
|
||||
gboolean valid_utf8;
|
||||
gchar *detected_encoding;
|
||||
gchar *encoding;
|
||||
|
||||
gboolean first_buffer;
|
||||
};
|
||||
|
||||
struct _GstTtmlParseClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_ttml_parse_get_type (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_TTML_PARSE_H__ */
|
53
ext/ttml/gstttmlplugin.c
Normal file
53
ext/ttml/gstttmlplugin.c
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) 2004 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
||||
* Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) <2015> British Broadcasting Corporation <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "gstttmlparse.h"
|
||||
#include "gstttmlrender.h"
|
||||
|
||||
GST_DEBUG_CATEGORY (ttmlparse_debug);
|
||||
GST_DEBUG_CATEGORY (ttmlrender_debug);
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_element_register (plugin, "ttmlparse", GST_RANK_PRIMARY,
|
||||
GST_TYPE_TTML_PARSE))
|
||||
return FALSE;
|
||||
if (!gst_element_register (plugin, "ttmlrender", GST_RANK_PRIMARY,
|
||||
GST_TYPE_TTML_RENDER))
|
||||
return FALSE;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (ttmlparse_debug, "ttmlparse", 0, "TTML parser");
|
||||
GST_DEBUG_CATEGORY_INIT (ttmlrender_debug, "ttmlrender", 0, "TTML renderer");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
ttmlsubs,
|
||||
"TTML subtitle handling",
|
||||
plugin_init, VERSION, "LGPL", "gst-ttml", "http://www.bbc.co.uk/rd")
|
2456
ext/ttml/gstttmlrender.c
Normal file
2456
ext/ttml/gstttmlrender.c
Normal file
File diff suppressed because it is too large
Load diff
124
ext/ttml/gstttmlrender.h
Normal file
124
ext/ttml/gstttmlrender.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
* Copyright (C) <2003> David Schleef <ds@schleef.org>
|
||||
* Copyright (C) <2006> Julien Moutte <julien@moutte.net>
|
||||
* Copyright (C) <2006> Zeeshan Ali <zeeshan.ali@nokia.com>
|
||||
* Copyright (C) <2006-2008> Tim-Philipp Müller <tim centricular net>
|
||||
* Copyright (C) <2009> Young-Ho Cha <ganadist@gmail.com>
|
||||
* Copyright (C) <2015> British Broadcasting Corporation <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_TTML_RENDER_H__
|
||||
#define __GST_TTML_RENDER_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include <pango/pango.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_TTML_RENDER (gst_ttml_render_get_type())
|
||||
#define GST_TTML_RENDER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\
|
||||
GST_TYPE_TTML_RENDER, GstTtmlRender))
|
||||
#define GST_TTML_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\
|
||||
GST_TYPE_TTML_RENDER, \
|
||||
GstTtmlRenderClass))
|
||||
#define GST_TTML_RENDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\
|
||||
GST_TYPE_TTML_RENDER, \
|
||||
GstTtmlRenderClass))
|
||||
#define GST_IS_TTML_RENDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
|
||||
GST_TYPE_TTML_RENDER))
|
||||
#define GST_IS_TTML_RENDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
|
||||
GST_TYPE_TTML_RENDER))
|
||||
|
||||
typedef struct _GstTtmlRender GstTtmlRender;
|
||||
typedef struct _GstTtmlRenderClass GstTtmlRenderClass;
|
||||
typedef struct _GstTtmlRenderRenderedImage GstTtmlRenderRenderedImage;
|
||||
typedef struct _GstTtmlRenderRenderedText GstTtmlRenderRenderedText;
|
||||
|
||||
struct _GstTtmlRenderRenderedImage {
|
||||
GstBuffer *image;
|
||||
gint x;
|
||||
gint y;
|
||||
guint width;
|
||||
guint height;
|
||||
};
|
||||
|
||||
struct _GstTtmlRenderRenderedText {
|
||||
GstTtmlRenderRenderedImage *text_image;
|
||||
|
||||
/* In order to get the positions of characters within a paragraph rendered by
|
||||
* pango we need to retain a reference to the PangoLayout object that was
|
||||
* used to render that paragraph. */
|
||||
PangoLayout *layout;
|
||||
|
||||
/* The coordinates in @layout will be offset horizontally with respect to the
|
||||
* position of those characters in @text_image. Store that offset here so
|
||||
* that the information in @layout can be used to locate the position and
|
||||
* extent of text areas in @text_image. */
|
||||
guint horiz_offset;
|
||||
};
|
||||
|
||||
|
||||
struct _GstTtmlRender {
|
||||
GstElement element;
|
||||
|
||||
GstPad *video_sinkpad;
|
||||
GstPad *text_sinkpad;
|
||||
GstPad *srcpad;
|
||||
|
||||
GstSegment segment;
|
||||
GstSegment text_segment;
|
||||
GstBuffer *text_buffer;
|
||||
gboolean text_linked;
|
||||
gboolean video_flushing;
|
||||
gboolean video_eos;
|
||||
gboolean text_flushing;
|
||||
gboolean text_eos;
|
||||
|
||||
GMutex lock;
|
||||
GCond cond; /* to signal removal of a queued text
|
||||
* buffer, arrival of a text buffer,
|
||||
* a text segment update, or a change
|
||||
* in status (e.g. shutdown, flushing) */
|
||||
|
||||
GstVideoInfo info;
|
||||
GstVideoFormat format;
|
||||
gint width;
|
||||
gint height;
|
||||
|
||||
gboolean want_background;
|
||||
gboolean wait_text;
|
||||
|
||||
gboolean need_render;
|
||||
|
||||
GList * compositions;
|
||||
};
|
||||
|
||||
struct _GstTtmlRenderClass {
|
||||
GstElementClass parent_class;
|
||||
|
||||
PangoContext *pango_context;
|
||||
GMutex *pango_lock;
|
||||
};
|
||||
|
||||
GType gst_ttml_render_get_type(void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_TTML_RENDER_H */
|
312
ext/ttml/subtitle.c
Normal file
312
ext/ttml/subtitle.c
Normal file
|
@ -0,0 +1,312 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
* Author: Chris Bass <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstsubtitle
|
||||
* @short_description: Library for describing sets of static subtitles.
|
||||
*
|
||||
* This library enables the description of static text scenes made up of a
|
||||
* number of regions, which may contain a number of block and inline text
|
||||
* elements. It is derived from the concepts and features defined in the Timed
|
||||
* Text Markup Language 1 (TTML1), Second Edition
|
||||
* (http://www.w3.org/TR/ttaf1-dfxp), and the EBU-TT-D profile of TTML1
|
||||
* (https://tech.ebu.ch/files/live/sites/tech/files/shared/tech/tech3380.pdf).
|
||||
*/
|
||||
|
||||
#include "subtitle.h"
|
||||
|
||||
/**
|
||||
* gst_subtitle_style_set_new:
|
||||
*
|
||||
* Create a new #GstSubtitleStyleSet with default values for all properties.
|
||||
*
|
||||
* Returns: (transfer full): A newly-allocated #GstSubtitleStyleSet.
|
||||
*/
|
||||
GstSubtitleStyleSet *
|
||||
gst_subtitle_style_set_new (void)
|
||||
{
|
||||
GstSubtitleStyleSet *ret = g_slice_new0 (GstSubtitleStyleSet);
|
||||
GstSubtitleColor white = { 255, 255, 255, 255 };
|
||||
GstSubtitleColor transparent = { 0, 0, 0, 0 };
|
||||
|
||||
ret->font_family = g_strdup ("default");
|
||||
ret->font_size = 1.0;
|
||||
ret->line_height = 1.25;
|
||||
ret->color = white;
|
||||
ret->background_color = transparent;
|
||||
ret->line_padding = 0.0;
|
||||
ret->origin_x = ret->origin_y = 0.0;
|
||||
ret->extent_w = ret->extent_h = 0.0;
|
||||
ret->padding_start = ret->padding_end
|
||||
= ret->padding_before = ret->padding_after = 0.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_style_set_free:
|
||||
* @style_set: A #GstSubtitleStyleSet.
|
||||
*
|
||||
* Free @style_set and its associated memory.
|
||||
*/
|
||||
void
|
||||
gst_subtitle_style_set_free (GstSubtitleStyleSet * style_set)
|
||||
{
|
||||
g_return_if_fail (style_set != NULL);
|
||||
g_free (style_set->font_family);
|
||||
g_slice_free (GstSubtitleStyleSet, style_set);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_gst_subtitle_element_free (GstSubtitleElement * element)
|
||||
{
|
||||
g_return_if_fail (element != NULL);
|
||||
gst_subtitle_style_set_free (element->style_set);
|
||||
g_slice_free (GstSubtitleElement, element);
|
||||
}
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleElement, gst_subtitle_element);
|
||||
|
||||
/**
|
||||
* gst_subtitle_element_new:
|
||||
* @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
|
||||
* and layout associated with this inline text element.
|
||||
* @text_index: The index within a #GstBuffer of the #GstMemory that contains
|
||||
* the text of this inline text element.
|
||||
*
|
||||
* Allocates a new #GstSubtitleElement.
|
||||
*
|
||||
* Returns: (transfer full): A newly-allocated #GstSubtitleElement. Unref
|
||||
* with gst_subtitle_element_unref() when no longer needed.
|
||||
*/
|
||||
GstSubtitleElement *
|
||||
gst_subtitle_element_new (GstSubtitleStyleSet * style_set,
|
||||
guint text_index, gboolean suppress_whitespace)
|
||||
{
|
||||
GstSubtitleElement *element;
|
||||
|
||||
g_return_val_if_fail (style_set != NULL, NULL);
|
||||
|
||||
element = g_slice_new0 (GstSubtitleElement);
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (element), 0,
|
||||
gst_subtitle_element_get_type (), NULL, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_subtitle_element_free);
|
||||
|
||||
element->style_set = style_set;
|
||||
element->text_index = text_index;
|
||||
element->suppress_whitespace = suppress_whitespace;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
static void
|
||||
_gst_subtitle_block_free (GstSubtitleBlock * block)
|
||||
{
|
||||
g_return_if_fail (block != NULL);
|
||||
gst_subtitle_style_set_free (block->style_set);
|
||||
g_ptr_array_unref (block->elements);
|
||||
g_slice_free (GstSubtitleBlock, block);
|
||||
}
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleBlock, gst_subtitle_block);
|
||||
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_new:
|
||||
* @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
|
||||
* and layout associated with this block of text elements.
|
||||
*
|
||||
* Allocates a new #GstSubtitleBlock.
|
||||
*
|
||||
* Returns: (transfer full): A newly-allocated #GstSubtitleBlock. Unref
|
||||
* with gst_subtitle_block_unref() when no longer needed.
|
||||
*/
|
||||
GstSubtitleBlock *
|
||||
gst_subtitle_block_new (GstSubtitleStyleSet * style_set)
|
||||
{
|
||||
GstSubtitleBlock *block;
|
||||
|
||||
g_return_val_if_fail (style_set != NULL, NULL);
|
||||
|
||||
block = g_slice_new0 (GstSubtitleBlock);
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (block), 0,
|
||||
gst_subtitle_block_get_type (), NULL, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_subtitle_block_free);
|
||||
|
||||
block->style_set = style_set;
|
||||
block->elements = g_ptr_array_new_with_free_func (
|
||||
(GDestroyNotify) gst_subtitle_element_unref);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_add_element:
|
||||
* @block: A #GstSubtitleBlock.
|
||||
* @element: (transfer full): A #GstSubtitleElement to add.
|
||||
*
|
||||
* Adds a #GstSubtitleElement to @block.
|
||||
*/
|
||||
void
|
||||
gst_subtitle_block_add_element (GstSubtitleBlock * block,
|
||||
GstSubtitleElement * element)
|
||||
{
|
||||
g_return_if_fail (block != NULL);
|
||||
g_return_if_fail (element != NULL);
|
||||
|
||||
g_ptr_array_add (block->elements, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_get_element_count:
|
||||
* @block: A #GstSubtitleBlock.
|
||||
*
|
||||
* Returns: The number of #GstSubtitleElements in @block.
|
||||
*/
|
||||
guint
|
||||
gst_subtitle_block_get_element_count (const GstSubtitleBlock * block)
|
||||
{
|
||||
g_return_val_if_fail (block != NULL, 0);
|
||||
|
||||
return block->elements->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_get_element:
|
||||
* @block: A #GstSubtitleBlock.
|
||||
* @index: Index of the element to get.
|
||||
*
|
||||
* Gets the #GstSubtitleElement at @index in the array of elements held by
|
||||
* @block.
|
||||
*
|
||||
* Returns: (transfer none): The #GstSubtitleElement at @index in the array of
|
||||
* elements held by @block, or %NULL if @index is out-of-bounds. The
|
||||
* function does not return a reference; the caller should obtain a reference
|
||||
* using gst_subtitle_element_ref(), if needed.
|
||||
*/
|
||||
const GstSubtitleElement *
|
||||
gst_subtitle_block_get_element (const GstSubtitleBlock * block, guint index)
|
||||
{
|
||||
g_return_val_if_fail (block != NULL, NULL);
|
||||
|
||||
if (index >= block->elements->len)
|
||||
return NULL;
|
||||
else
|
||||
return g_ptr_array_index (block->elements, index);
|
||||
}
|
||||
|
||||
static void
|
||||
_gst_subtitle_region_free (GstSubtitleRegion * region)
|
||||
{
|
||||
g_return_if_fail (region != NULL);
|
||||
gst_subtitle_style_set_free (region->style_set);
|
||||
g_ptr_array_unref (region->blocks);
|
||||
g_slice_free (GstSubtitleRegion, region);
|
||||
}
|
||||
|
||||
GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleRegion, gst_subtitle_region);
|
||||
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_new:
|
||||
* @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
|
||||
* and layout associated with this region.
|
||||
*
|
||||
* Allocates a new #GstSubtitleRegion.
|
||||
*
|
||||
* Returns: (transfer full): A newly-allocated #GstSubtitleRegion. Unref
|
||||
* with gst_subtitle_region_unref() when no longer needed.
|
||||
*/
|
||||
GstSubtitleRegion *
|
||||
gst_subtitle_region_new (GstSubtitleStyleSet * style_set)
|
||||
{
|
||||
GstSubtitleRegion *region;
|
||||
|
||||
g_return_val_if_fail (style_set != NULL, NULL);
|
||||
|
||||
region = g_slice_new0 (GstSubtitleRegion);
|
||||
gst_mini_object_init (GST_MINI_OBJECT_CAST (region), 0,
|
||||
gst_subtitle_region_get_type (), NULL, NULL,
|
||||
(GstMiniObjectFreeFunction) _gst_subtitle_region_free);
|
||||
|
||||
region->style_set = style_set;
|
||||
region->blocks = g_ptr_array_new_with_free_func (
|
||||
(GDestroyNotify) gst_subtitle_block_unref);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_add_block:
|
||||
* @region: A #GstSubtitleRegion.
|
||||
* @block: (transfer full): A #GstSubtitleBlock which should be added
|
||||
* to @region's array of blocks.
|
||||
*
|
||||
* Adds a #GstSubtitleBlock to the end of the array of blocks held by @region.
|
||||
* @region will take ownership of @block, and will unref it when @region
|
||||
* is freed.
|
||||
*/
|
||||
void
|
||||
gst_subtitle_region_add_block (GstSubtitleRegion * region,
|
||||
GstSubtitleBlock * block)
|
||||
{
|
||||
g_return_if_fail (region != NULL);
|
||||
g_return_if_fail (block != NULL);
|
||||
|
||||
g_ptr_array_add (region->blocks, block);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_get_block_count:
|
||||
* @region: A #GstSubtitleRegion.
|
||||
*
|
||||
* Returns: The number of blocks in @region.
|
||||
*/
|
||||
guint
|
||||
gst_subtitle_region_get_block_count (const GstSubtitleRegion * region)
|
||||
{
|
||||
g_return_val_if_fail (region != NULL, 0);
|
||||
|
||||
return region->blocks->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_get_block:
|
||||
* @region: A #GstSubtitleRegion.
|
||||
* @index: Index of the block to get.
|
||||
*
|
||||
* Gets the block at @index in the array of blocks held by @region.
|
||||
*
|
||||
* Returns: (transfer none): The #GstSubtitleBlock at @index in the array of
|
||||
* blocks held by @region, or %NULL if @index is out-of-bounds. The
|
||||
* function does not return a reference; the caller should obtain a reference
|
||||
* using gst_subtitle_block_ref(), if needed.
|
||||
*/
|
||||
const GstSubtitleBlock *
|
||||
gst_subtitle_region_get_block (const GstSubtitleRegion * region, guint index)
|
||||
{
|
||||
g_return_val_if_fail (region != NULL, NULL);
|
||||
|
||||
if (index >= region->blocks->len)
|
||||
return NULL;
|
||||
else
|
||||
return g_ptr_array_index (region->blocks, index);
|
||||
}
|
592
ext/ttml/subtitle.h
Normal file
592
ext/ttml/subtitle.h
Normal file
|
@ -0,0 +1,592 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
* Author: Chris Bass <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_SUBTITLE_H__
|
||||
#define __GST_SUBTITLE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <gst/gst.h>
|
||||
#include <gst/gstminiobject.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstSubtitleColor GstSubtitleColor;
|
||||
typedef struct _GstSubtitleStyleSet GstSubtitleStyleSet;
|
||||
typedef struct _GstSubtitleElement GstSubtitleElement;
|
||||
typedef struct _GstSubtitleBlock GstSubtitleBlock;
|
||||
typedef struct _GstSubtitleRegion GstSubtitleRegion;
|
||||
|
||||
/**
|
||||
* GstSubtitleWritingMode:
|
||||
* @GST_SUBTITLE_WRITING_MODE_LRTB: Text progression is left-to-right,
|
||||
* top-to-bottom.
|
||||
* @GST_SUBTITLE_WRITING_MODE_RLTB: Text progression is right-to-left,
|
||||
* top-to-bottom.
|
||||
* @GST_SUBTITLE_WRITING_MODE_TBRL: Text progression is top-to-bottom,
|
||||
* right-to-left.
|
||||
* @GST_SUBTITLE_WRITING_MODE_TBLR: Text progression is top-to-bottom,
|
||||
* left-to-right.
|
||||
*
|
||||
* Writing mode of text content. The values define the direction of progression
|
||||
* of both inline text (#GstSubtitleElements) and blocks of text
|
||||
* (#GstSubtitleBlocks).
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_WRITING_MODE_LRTB,
|
||||
GST_SUBTITLE_WRITING_MODE_RLTB,
|
||||
GST_SUBTITLE_WRITING_MODE_TBRL,
|
||||
GST_SUBTITLE_WRITING_MODE_TBLR
|
||||
} GstSubtitleWritingMode;
|
||||
|
||||
/**
|
||||
* GstSubtitleDisplayAlign:
|
||||
* @GST_SUBTITLE_DISPLAY_ALIGN_BEFORE: Blocks should be aligned at the start of
|
||||
* the containing region.
|
||||
* @GST_SUBTITLE_DISPLAY_ALIGN_CENTER: Blocks should be aligned in the center
|
||||
* of the containing region.
|
||||
* @GST_SUBTITLE_DISPLAY_ALIGN_AFTER: Blocks should be aligned to the end of
|
||||
* the containing region.
|
||||
*
|
||||
* Defines the alignment of text blocks within a region in the direction in
|
||||
* which blocks are being stacked. For text that is written left-to-right and
|
||||
* top-to-bottom, this corresponds to the vertical alignment of text blocks.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_DISPLAY_ALIGN_BEFORE,
|
||||
GST_SUBTITLE_DISPLAY_ALIGN_CENTER,
|
||||
GST_SUBTITLE_DISPLAY_ALIGN_AFTER
|
||||
} GstSubtitleDisplayAlign;
|
||||
|
||||
/**
|
||||
* GstSubtitleBackgroundMode:
|
||||
* @GST_SUBTITLE_BACKGROUND_MODE_ALWAYS: Background rectangle should be visible
|
||||
* at all times.
|
||||
* @GST_SUBTITLE_BACKGROUND_MODE_WHEN_ACTIVE: Background rectangle should be
|
||||
* visible only when text is rendered into the corresponding region.
|
||||
*
|
||||
* Defines whether the background rectangle of a region should be visible at
|
||||
* all times or only when text is rendered within it.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_BACKGROUND_MODE_ALWAYS,
|
||||
GST_SUBTITLE_BACKGROUND_MODE_WHEN_ACTIVE
|
||||
} GstSubtitleBackgroundMode;
|
||||
|
||||
/**
|
||||
* GstSubtitleOverflowMode:
|
||||
* @GST_SUBTITLE_OVERFLOW_MODE_HIDDEN: If text and/or background rectangles
|
||||
* flowed into the region overflow the bounds of that region, they should
|
||||
* be clipped at the region boundary.
|
||||
* @GST_SUBTITLE_OVERFLOW_MODE_VISIBLE: If text and/or background rectangles
|
||||
* flowed into the region overflow the bounds of that region, they should be
|
||||
* allowed to overflow the region boundary.
|
||||
*
|
||||
* Defines what should happen to text that overflows its containing region.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_OVERFLOW_MODE_HIDDEN,
|
||||
GST_SUBTITLE_OVERFLOW_MODE_VISIBLE
|
||||
} GstSubtitleOverflowMode;
|
||||
|
||||
/**
|
||||
* GstSubtitleColor:
|
||||
* @r: Red value.
|
||||
* @g: Green value.
|
||||
* @b: Blue value.
|
||||
* @a: Alpha value (0 = totally transparent; 255 = totally opaque).
|
||||
*
|
||||
* Describes an RGBA color.
|
||||
*/
|
||||
struct _GstSubtitleColor {
|
||||
guint8 r;
|
||||
guint8 g;
|
||||
guint8 b;
|
||||
guint8 a;
|
||||
};
|
||||
|
||||
/**
|
||||
* GstSubtitleTextDirection:
|
||||
* @GST_SUBTITLE_TEXT_DIRECTION_LTR: Text direction is left-to-right.
|
||||
* @GST_SUBTITLE_TEXT_DIRECTION_RTL: Text direction is right-to-left.
|
||||
*
|
||||
* Defines the progression direction of unicode text that is being treated by
|
||||
* the unicode bidirectional algorithm as embedded or overidden (see
|
||||
* http://unicode.org/reports/tr9/ for more details of the unicode
|
||||
* bidirectional algorithm).
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_TEXT_DIRECTION_LTR,
|
||||
GST_SUBTITLE_TEXT_DIRECTION_RTL
|
||||
} GstSubtitleTextDirection;
|
||||
|
||||
/**
|
||||
* GstSubtitleTextAlign:
|
||||
* @GST_SUBTITLE_TEXT_ALIGN_START: Text areas should be rendered at the
|
||||
* start of the block area, with respect to the direction in which text is
|
||||
* being rendered. For text that is rendered left-to-right this corresponds to
|
||||
* the left of the block area; for text that is rendered right-to-left this
|
||||
* corresponds to the right of the block area.
|
||||
* @GST_SUBTITLE_TEXT_ALIGN_LEFT: Text areas should be rendered at the left of
|
||||
* the block area.
|
||||
* @GST_SUBTITLE_TEXT_ALIGN_CENTER: Text areas should be rendered at the center
|
||||
* of the block area.
|
||||
* @GST_SUBTITLE_TEXT_ALIGN_RIGHT: Text areas should be rendered at the right
|
||||
* of the block area.
|
||||
* @GST_SUBTITLE_TEXT_ALIGN_END: Text areas should be rendered at the end of
|
||||
* the block area, with respect to the direction in which text is being
|
||||
* rendered. For text that is rendered left-to-right this corresponds to the
|
||||
* right of the block area; for text that is rendered right-to-left this
|
||||
* corresponds to end of the block area.
|
||||
*
|
||||
* Defines how inline text areas within a block should be aligned within the
|
||||
* block area.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_TEXT_ALIGN_START,
|
||||
GST_SUBTITLE_TEXT_ALIGN_LEFT,
|
||||
GST_SUBTITLE_TEXT_ALIGN_CENTER,
|
||||
GST_SUBTITLE_TEXT_ALIGN_RIGHT,
|
||||
GST_SUBTITLE_TEXT_ALIGN_END
|
||||
} GstSubtitleTextAlign;
|
||||
|
||||
/**
|
||||
* GstSubtitleFontStyle:
|
||||
* @GST_SUBTITLE_FONT_STYLE_NORMAL: Normal font style.
|
||||
* @GST_SUBTITLE_FONT_STYLE_ITALIC: Italic font style.
|
||||
*
|
||||
* Defines styling that should be applied to the glyphs of a font used to
|
||||
* render text within an inline text element.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_FONT_STYLE_NORMAL,
|
||||
GST_SUBTITLE_FONT_STYLE_ITALIC
|
||||
} GstSubtitleFontStyle;
|
||||
|
||||
/**
|
||||
* GstSubtitleFontWeight:
|
||||
* @GST_SUBTITLE_FONT_WEIGHT_NORMAL: Normal weight.
|
||||
* @GST_SUBTITLE_FONT_WEIGHT_BOLD: Bold weight.
|
||||
*
|
||||
* Defines the font weight that should be applied to the glyphs of a font used
|
||||
* to render text within an inline text element.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_FONT_WEIGHT_NORMAL,
|
||||
GST_SUBTITLE_FONT_WEIGHT_BOLD
|
||||
} GstSubtitleFontWeight;
|
||||
|
||||
/**
|
||||
* GstSubtitleTextDecoration:
|
||||
* @GST_SUBTITLE_TEXT_DECORATION_NONE: Text should not be decorated.
|
||||
* @GST_SUBTITLE_TEXT_DECORATION_UNDERLINE: Text should be underlined.
|
||||
*
|
||||
* Defines the decoration that should be applied to the glyphs of a font used
|
||||
* to render text within an inline text element.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_TEXT_DECORATION_NONE,
|
||||
GST_SUBTITLE_TEXT_DECORATION_UNDERLINE
|
||||
} GstSubtitleTextDecoration;
|
||||
|
||||
/**
|
||||
* GstSubtitleUnicodeBidi:
|
||||
* @GST_SUBTITLE_UNICODE_BIDI_NORMAL: Text should progress according the the
|
||||
* default behaviour of the Unicode bidirectional algorithm.
|
||||
* @GST_SUBTITLE_UNICODE_BIDI_EMBED: Text should be treated as being embedded
|
||||
* with a specific direction (given by a #GstSubtitleTextDecoration value
|
||||
* defined elsewhere).
|
||||
* @GST_SUBTITLE_UNICODE_BIDI_OVERRIDE: Text should be forced to have a
|
||||
* specific direction (given by a #GstSubtitleTextDecoration value defined
|
||||
* elsewhere).
|
||||
*
|
||||
* Defines directional embedding or override according to the Unicode
|
||||
* bidirectional algorithm. See http://unicode.org/reports/tr9/ for more
|
||||
* details of the Unicode bidirectional algorithm.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_UNICODE_BIDI_NORMAL,
|
||||
GST_SUBTITLE_UNICODE_BIDI_EMBED,
|
||||
GST_SUBTITLE_UNICODE_BIDI_OVERRIDE
|
||||
} GstSubtitleUnicodeBidi;
|
||||
|
||||
/**
|
||||
* GstSubtitleWrapping:
|
||||
* @GST_SUBTITLE_WRAPPING_ON: Lines that overflow the region boundary should be
|
||||
* wrapped.
|
||||
* @GST_SUBTITLE_WRAPPING_OFF: Lines that overflow the region boundary should
|
||||
* not be wrapped.
|
||||
*
|
||||
* Defines how a renderer should treat lines of text that overflow the boundary
|
||||
* of the region into which they are being rendered.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_WRAPPING_ON,
|
||||
GST_SUBTITLE_WRAPPING_OFF
|
||||
} GstSubtitleWrapping;
|
||||
|
||||
/**
|
||||
* GstSubtitleMultiRowAlign:
|
||||
* @GST_SUBTITLE_MULTI_ROW_ALIGN_AUTO: Lines should be aligned according to the
|
||||
* value of #GstSubtitleTextAlign associated with that text.
|
||||
* @GST_SUBTITLE_MULTI_ROW_ALIGN_START: Lines should be aligned at their
|
||||
* starting edge. The edge that is considered the starting edge depends upon
|
||||
* the direction of that text.
|
||||
* @GST_SUBTITLE_MULTI_ROW_ALIGN_CENTER: Lines should be center-aligned.
|
||||
* @GST_SUBTITLE_MULTI_ROW_ALIGN_END: Lines should be aligned at their trailing
|
||||
* edge. The edge that is considered the trailing edge depends upon the
|
||||
* direction of that text.
|
||||
*
|
||||
* Defines how multiple 'rows' (i.e, lines) in a block should be aligned
|
||||
* relative to each other.
|
||||
*
|
||||
* This is based upon the ebutts:multiRowAlign attribute defined in the
|
||||
* EBU-TT-D specification.
|
||||
*/
|
||||
typedef enum {
|
||||
GST_SUBTITLE_MULTI_ROW_ALIGN_AUTO,
|
||||
GST_SUBTITLE_MULTI_ROW_ALIGN_START,
|
||||
GST_SUBTITLE_MULTI_ROW_ALIGN_CENTER,
|
||||
GST_SUBTITLE_MULTI_ROW_ALIGN_END
|
||||
} GstSubtitleMultiRowAlign;
|
||||
|
||||
/**
|
||||
* GstSubtitleStyleSet:
|
||||
* @text_direction: Defines the direction of text that has been declared by the
|
||||
* #GstSubtitleStyleSet:unicode_bidi attribute to be embbedded or overridden.
|
||||
* Applies to both #GstSubtitleBlocks and #GstSubtitleElements.
|
||||
* @font_family: The name of the font family that should be used to render the
|
||||
* text of an inline element. Applies only to #GstSubtitleElements.
|
||||
* @font_size: The size of the font that should be used to render the text
|
||||
* of an inline element. The size is given as a multiple of the display height,
|
||||
* where 1.0 equals the height of the display. Applies only to
|
||||
* #GstSubtitleElements.
|
||||
* @line_height: The inter-baseline separation between lines generated when
|
||||
* rendering inline text elements within a block area. The height is given as a
|
||||
* multiple of the the overall display height, where 1.0 equals the height of
|
||||
* the display. Applies only to #GstSubtitleBlocks.
|
||||
* @text_align: Controls the alignent of lines of text within a block area.
|
||||
* Note that this attribute does not control the alignment of lines relative to
|
||||
* each other within a block area: that is determined by
|
||||
* #GstSubtitleStyleSet:multi_row_align. Applies only to #GstSubtitleBlocks.
|
||||
* @color: The color that should be used when rendering the text of an inline
|
||||
* element. Applies only to #GstSubtitleElements.
|
||||
* @background_color: The color of the rectangle that should be rendered behind
|
||||
* the contents of a #GstSubtitleRegion, #GstSubtitleBlock or
|
||||
* #GstSubtitleElement.
|
||||
* @font_style: The style of the font that should be used to render the text
|
||||
* of an inline element. Applies only to #GstSubtitleElements.
|
||||
* @font_weight: The weight of the font that should be used to render the text
|
||||
* of an inline element. Applies only to #GstSubtitleElements.
|
||||
* @text_decoration: The decoration that should be applied to the text of an
|
||||
* inline element. Applies only to #GstSubtitleElements.
|
||||
* @unicode_bidi: Controls how unicode text within a block or inline element
|
||||
* should be treated by the unicode bidirectional algorithm. Applies to both
|
||||
* #GstSubtitleBlocks and #GstSubtitleElements.
|
||||
* @wrap_option: Defines whether or not automatic line breaking should apply to
|
||||
* the lines generated when rendering a block of text elements. Applies only to
|
||||
* #GstSubtitleBlocks.
|
||||
* @multi_row_align: Defines how 'rows' (i.e., lines) within a text block
|
||||
* should be aligned relative to each other. Note that this attribute does not
|
||||
* determine how a block of text is aligned within that block area: that is
|
||||
* determined by @text_align. Applies only to #GstSubtitleBlocks.
|
||||
* @line_padding: Defines how much horizontal padding should be added on the
|
||||
* start and end of each rendered line; this allows the insertion of space
|
||||
* between the start/end of text lines and their background rectangles for
|
||||
* better-looking subtitles. This is based upon the ebutts:linePadding
|
||||
* attribute defined in the EBU-TT-D specification. Applies only to
|
||||
* #GstSubtitleBlocks.
|
||||
* @origin_x: The horizontal origin of a region into which text blocks may be
|
||||
* rendered. Given as a multiple of the overall display width, where 1.0 equals
|
||||
* the width of the display. Applies only to #GstSubtitleRegions.
|
||||
* @origin_y: The vertical origin of a region into which text blocks may be
|
||||
* rendered. Given as a multiple of the overall display height, where 1.0
|
||||
* equals the height of the display. Applies only to #GstSubtitleRegions.
|
||||
* @extent_w: The horizontal extent of a region into which text blocks may be
|
||||
* rendered. Given as a multiple of the overall display width, where 1.0 equals
|
||||
* the width of the display. Applies only to #GstSubtitleRegions.
|
||||
* @extent_h: The vertical extent of a region into which text blocks may be
|
||||
* rendered. Given as a multiple of the overall display height, where 1.0
|
||||
* equals the height of the display. Applies only to #GstSubtitleRegions.
|
||||
* @display_align: The alignment of generated text blocks in the direction in
|
||||
* which blocks are being stacked. For text that flows left-to-right and
|
||||
* top-to-bottom, for example, this corresponds to the vertical alignment of
|
||||
* text blocks. Applies only to #GstSubtitleRegions.
|
||||
* @padding_start: The horizontal indent of text from the leading edge of a
|
||||
* region into which blocks may be rendered. Given as a multiple of the overall
|
||||
* display width, where 1.0 equals the width of the display. Applies only to
|
||||
* #GstSubtitleRegions.
|
||||
* @padding_end: The horizontal indent of text from the trailing edge of a
|
||||
* region into which blocks may be rendered. Given as a multiple of the overall
|
||||
* display width, where 1.0 equals the width of the display. Applies only to
|
||||
* #GstSubtitleRegions.
|
||||
* @padding_before: The vertical indent of text from the top edge of a region
|
||||
* into which blocks may be rendered. Given as a multiple of the overall
|
||||
* display height, where 1.0 equals the height of the display. Applies only to
|
||||
* #GstSubtitleRegions.
|
||||
* @padding_after: The vertical indent of text from the bottom edge of a
|
||||
* region into which blocks may be rendered. Given as a multiple of the overall
|
||||
* display height, where 1.0 equals the height of the display. Applies only to
|
||||
* #GstSubtitleRegions.
|
||||
* @writing_mode: Defines the direction in which both inline elements and
|
||||
* blocks should be stacked when rendered into an on-screen region. Applies
|
||||
* only to #GstSubtitleRegions.
|
||||
* @show_background: Defines whether the background of a region should be
|
||||
* displayed at all times or only when it has text rendered into it. Applies
|
||||
* only to #GstSubtitleRegions.
|
||||
* @overflow: Defines what should happen if text and background rectangles
|
||||
* generated by rendering text blocks overflow the size of their containing
|
||||
* region. Applies only to #GstSubtitleRegions.
|
||||
*
|
||||
* Holds a set of attributes that describes the styling and layout that apply
|
||||
* to #GstSubtitleRegion, #GstSubtitleBlock and/or #GstSubtitleElement objects.
|
||||
*
|
||||
* Note that, though each of the above object types have an associated
|
||||
* #GstSubtitleStyleSet, not all attributes in a #GstSubtitleStyleSet type
|
||||
* apply to all object types: #GstSubtitleStyleSet:overflow applies only to
|
||||
* #GstSubtitleRegions, for example, while #GstSubtitleStyleSet:font_style
|
||||
* applies only to #GstSubtitleElements. Some attributes apply to multiple
|
||||
* object types: #GstSubtitleStyleSet:background_color, for example, applies to
|
||||
* all object types. The types to which each attribute applies is given in the
|
||||
* description of that attribute below.
|
||||
*/
|
||||
struct _GstSubtitleStyleSet {
|
||||
GstSubtitleTextDirection text_direction;
|
||||
gchar *font_family;
|
||||
gdouble font_size;
|
||||
gdouble line_height;
|
||||
GstSubtitleTextAlign text_align;
|
||||
GstSubtitleColor color;
|
||||
GstSubtitleColor background_color;
|
||||
GstSubtitleFontStyle font_style;
|
||||
GstSubtitleFontWeight font_weight;
|
||||
GstSubtitleTextDecoration text_decoration;
|
||||
GstSubtitleUnicodeBidi unicode_bidi;
|
||||
GstSubtitleWrapping wrap_option;
|
||||
GstSubtitleMultiRowAlign multi_row_align;
|
||||
gdouble line_padding;
|
||||
gdouble origin_x, origin_y;
|
||||
gdouble extent_w, extent_h;
|
||||
GstSubtitleDisplayAlign display_align;
|
||||
gdouble padding_start, padding_end, padding_before, padding_after;
|
||||
GstSubtitleWritingMode writing_mode;
|
||||
GstSubtitleBackgroundMode show_background;
|
||||
GstSubtitleOverflowMode overflow;
|
||||
};
|
||||
|
||||
GstSubtitleStyleSet * gst_subtitle_style_set_new (void);
|
||||
|
||||
void gst_subtitle_style_set_free (GstSubtitleStyleSet * style_set);
|
||||
|
||||
|
||||
/**
|
||||
* GstSubtitleElement:
|
||||
* @mini_object: The parent #GstMiniObject.
|
||||
* @style_set: Styling associated with this element.
|
||||
* @text_index: Index into the #GstBuffer associated with this
|
||||
* #GstSubtitleElement; the index identifies the #GstMemory within the
|
||||
* #GstBuffer that holds the #GstSubtitleElement's text.
|
||||
* @suppress_whitespace: Indicates whether or not a renderer should suppress
|
||||
* whitespace in the element's text.
|
||||
*
|
||||
* Represents an inline text element.
|
||||
*
|
||||
* In TTML this would correspond to inline text resulting from a <span>
|
||||
* element, an anonymous span (e.g., text within a <p> tag), or a
|
||||
* <br> element.
|
||||
*/
|
||||
struct _GstSubtitleElement
|
||||
{
|
||||
GstMiniObject mini_object;
|
||||
|
||||
GstSubtitleStyleSet *style_set;
|
||||
guint text_index;
|
||||
gboolean suppress_whitespace;
|
||||
|
||||
/*< private >*/
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_subtitle_element_get_type (void);
|
||||
|
||||
GstSubtitleElement * gst_subtitle_element_new (GstSubtitleStyleSet * style_set,
|
||||
guint text_index, gboolean suppress_whitespace);
|
||||
|
||||
/**
|
||||
* gst_subtitle_element_ref:
|
||||
* @element: A #GstSubtitleElement.
|
||||
*
|
||||
* Increments the refcount of @element.
|
||||
*
|
||||
* Returns: (transfer full): @element.
|
||||
*/
|
||||
static inline GstSubtitleElement *
|
||||
gst_subtitle_element_ref (GstSubtitleElement * element)
|
||||
{
|
||||
return (GstSubtitleElement *)
|
||||
gst_mini_object_ref (GST_MINI_OBJECT_CAST (element));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_element_unref:
|
||||
* @element: (transfer full): A #GstSubtitleElement.
|
||||
*
|
||||
* Decrements the refcount of @element. If the refcount reaches 0, @element
|
||||
* will be freed.
|
||||
*/
|
||||
static inline void
|
||||
gst_subtitle_element_unref (GstSubtitleElement * element)
|
||||
{
|
||||
gst_mini_object_unref (GST_MINI_OBJECT_CAST (element));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GstSubtitleBlock:
|
||||
* @mini_object: The parent #GstMiniObject.
|
||||
* @style_set: Styling associated with this block.
|
||||
*
|
||||
* Represents a text block made up of one or more inline text elements (i.e.,
|
||||
* one or more #GstSubtitleElements).
|
||||
*
|
||||
* In TTML this would correspond to the block of text resulting from the inline
|
||||
* elements within a single <p>.
|
||||
*/
|
||||
struct _GstSubtitleBlock
|
||||
{
|
||||
GstMiniObject mini_object;
|
||||
|
||||
GstSubtitleStyleSet *style_set;
|
||||
|
||||
/*< private >*/
|
||||
GPtrArray *elements;
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_subtitle_block_get_type (void);
|
||||
|
||||
GstSubtitleBlock * gst_subtitle_block_new (GstSubtitleStyleSet * style_set);
|
||||
|
||||
void gst_subtitle_block_add_element (
|
||||
GstSubtitleBlock * block,
|
||||
GstSubtitleElement * element);
|
||||
|
||||
guint gst_subtitle_block_get_element_count (const GstSubtitleBlock * block);
|
||||
|
||||
const GstSubtitleElement * gst_subtitle_block_get_element (
|
||||
const GstSubtitleBlock * block, guint index);
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_ref:
|
||||
* @block: A #GstSubtitleBlock.
|
||||
*
|
||||
* Increments the refcount of @block.
|
||||
*
|
||||
* Returns: (transfer full): @block.
|
||||
*/
|
||||
static inline GstSubtitleBlock *
|
||||
gst_subtitle_block_ref (GstSubtitleBlock * block)
|
||||
{
|
||||
return (GstSubtitleBlock *)
|
||||
gst_mini_object_ref (GST_MINI_OBJECT_CAST (block));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_block_unref:
|
||||
* @block: (transfer full): A #GstSubtitleBlock.
|
||||
*
|
||||
* Decrements the refcount of @block. If the refcount reaches 0, @block will
|
||||
* be freed.
|
||||
*/
|
||||
static inline void
|
||||
gst_subtitle_block_unref (GstSubtitleBlock * block)
|
||||
{
|
||||
gst_mini_object_unref (GST_MINI_OBJECT_CAST (block));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* GstSubtitleRegion:
|
||||
* @mini_object: The parent #GstMiniObject.
|
||||
* @style_set: Styling associated with this region.
|
||||
*
|
||||
* Represents an on-screen region in which is displayed zero or more
|
||||
* #GstSubtitleBlocks.
|
||||
*
|
||||
* In TTML this corresponds to a <region> into which zero or more
|
||||
* <p>s may be rendered. A #GstSubtitleRegion allows a background
|
||||
* rectangle to be displayed in a region area even if no text blocks are
|
||||
* rendered into it, as per the behaviour allowed by TTML regions whose
|
||||
* tts:showBackground style attribute is set to "always".
|
||||
*/
|
||||
struct _GstSubtitleRegion
|
||||
{
|
||||
GstMiniObject mini_object;
|
||||
|
||||
GstSubtitleStyleSet *style_set;
|
||||
|
||||
/*< private >*/
|
||||
GPtrArray *blocks;
|
||||
gpointer _gst_reserved[GST_PADDING];
|
||||
};
|
||||
|
||||
GType gst_subtitle_region_get_type (void);
|
||||
|
||||
GstSubtitleRegion * gst_subtitle_region_new (GstSubtitleStyleSet * style_set);
|
||||
|
||||
void gst_subtitle_region_add_block (
|
||||
GstSubtitleRegion * region,
|
||||
GstSubtitleBlock * block);
|
||||
|
||||
guint gst_subtitle_region_get_block_count (const GstSubtitleRegion * region);
|
||||
|
||||
const GstSubtitleBlock * gst_subtitle_region_get_block (
|
||||
const GstSubtitleRegion * region, guint index);
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_ref:
|
||||
* @region: A #GstSubtitleRegion.
|
||||
*
|
||||
* Increments the refcount of @region.
|
||||
*
|
||||
* Returns: (transfer full): @region.
|
||||
*/
|
||||
static inline GstSubtitleRegion *
|
||||
gst_subtitle_region_ref (GstSubtitleRegion * region)
|
||||
{
|
||||
return (GstSubtitleRegion *)
|
||||
gst_mini_object_ref (GST_MINI_OBJECT_CAST (region));
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_subtitle_region_unref:
|
||||
* @region: (transfer full): A #GstSubtitleRegion.
|
||||
*
|
||||
* Decrements the refcount of @region. If the refcount reaches 0, @region will
|
||||
* be freed.
|
||||
*/
|
||||
static inline void
|
||||
gst_subtitle_region_unref (GstSubtitleRegion * region)
|
||||
{
|
||||
gst_mini_object_unref (GST_MINI_OBJECT_CAST (region));
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SUBTITLE_H__ */
|
101
ext/ttml/subtitlemeta.c
Normal file
101
ext/ttml/subtitlemeta.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
* Author: Chris Bass <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gstsubtitlemeta
|
||||
* @short_description: Metadata class for timed-text subtitles.
|
||||
*
|
||||
* The GstSubtitleMeta class enables the layout and styling information needed
|
||||
* to render subtitle text to be attached to a #GstBuffer containing that text.
|
||||
*/
|
||||
|
||||
#include "subtitlemeta.h"
|
||||
|
||||
GType
|
||||
gst_subtitle_meta_api_get_type (void)
|
||||
{
|
||||
static volatile GType type;
|
||||
static const gchar *tags[] = { "memory", NULL };
|
||||
|
||||
if (g_once_init_enter (&type)) {
|
||||
GType _type = gst_meta_api_type_register ("GstSubtitleMetaAPI", tags);
|
||||
g_once_init_leave (&type, _type);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_subtitle_meta_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
|
||||
{
|
||||
GstSubtitleMeta *subtitle_meta = (GstSubtitleMeta *) meta;
|
||||
|
||||
subtitle_meta->regions = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_subtitle_meta_free (GstMeta * meta, GstBuffer * buffer)
|
||||
{
|
||||
GstSubtitleMeta *subtitle_meta = (GstSubtitleMeta *) meta;
|
||||
|
||||
if (subtitle_meta->regions)
|
||||
g_ptr_array_unref (subtitle_meta->regions);
|
||||
}
|
||||
|
||||
const GstMetaInfo *
|
||||
gst_subtitle_meta_get_info (void)
|
||||
{
|
||||
static const GstMetaInfo *subtitle_meta_info = NULL;
|
||||
|
||||
if (g_once_init_enter (&subtitle_meta_info)) {
|
||||
const GstMetaInfo *meta =
|
||||
gst_meta_register (GST_SUBTITLE_META_API_TYPE, "GstSubtitleMeta",
|
||||
sizeof (GstSubtitleMeta), gst_subtitle_meta_init,
|
||||
gst_subtitle_meta_free, (GstMetaTransformFunction) NULL);
|
||||
g_once_init_leave (&subtitle_meta_info, meta);
|
||||
}
|
||||
return subtitle_meta_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_buffer_add_subtitle_meta:
|
||||
* @buffer: (transfer none): #GstBuffer holding subtitle text, to which
|
||||
* subtitle metadata should be added.
|
||||
* @regions: (transfer full): A #GPtrArray of #GstSubtitleRegions.
|
||||
*
|
||||
* Attaches subtitle metadata to a #GstBuffer.
|
||||
*
|
||||
* Returns: A pointer to the added #GstSubtitleMeta if successful; %NULL if
|
||||
* unsuccessful.
|
||||
*/
|
||||
GstSubtitleMeta *
|
||||
gst_buffer_add_subtitle_meta (GstBuffer * buffer, GPtrArray * regions)
|
||||
{
|
||||
GstSubtitleMeta *meta;
|
||||
|
||||
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (regions != NULL, NULL);
|
||||
|
||||
meta = (GstSubtitleMeta *) gst_buffer_add_meta (buffer,
|
||||
GST_SUBTITLE_META_INFO, NULL);
|
||||
|
||||
meta->regions = regions;
|
||||
return meta;
|
||||
}
|
66
ext/ttml/subtitlemeta.h
Normal file
66
ext/ttml/subtitlemeta.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
* Author: Chris Bass <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_SUBTITLE_META_H__
|
||||
#define __GST_SUBTITLE_META_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "subtitle.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GstSubtitleMeta GstSubtitleMeta;
|
||||
|
||||
/**
|
||||
* GstSubtitleMeta:
|
||||
* @meta: The parent #GstMeta.
|
||||
* @regions: The #GstSubtitleRegions containing layout and styling information
|
||||
* needed to render the subtitle text contained in the associated #GstBuffer.
|
||||
*
|
||||
* Metadata type that describes the layout and styling of subtitle text
|
||||
* contained in a #GstBuffer.
|
||||
*/
|
||||
struct _GstSubtitleMeta {
|
||||
GstMeta meta;
|
||||
|
||||
GPtrArray *regions;
|
||||
};
|
||||
|
||||
GType gst_subtitle_meta_api_get_type (void);
|
||||
#define GST_SUBTITLE_META_API_TYPE (gst_subtitle_meta_api_get_type())
|
||||
|
||||
#define gst_buffer_get_subtitle_meta(b) \
|
||||
((GstSubtitleMeta*)gst_buffer_get_meta ((b), GST_SUBTITLE_META_API_TYPE))
|
||||
|
||||
#define GST_SUBTITLE_META_INFO (gst_subtitle_meta_get_info())
|
||||
|
||||
gboolean gst_subtitle_meta_init (GstMeta * meta, gpointer params,
|
||||
GstBuffer * buffer);
|
||||
|
||||
void gst_subtitle_meta_free (GstMeta * meta, GstBuffer * buffer);
|
||||
|
||||
const GstMetaInfo * gst_subtitle_meta_get_info (void);
|
||||
|
||||
GstSubtitleMeta * gst_buffer_add_subtitle_meta (GstBuffer * buffer,
|
||||
GPtrArray * regions);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_SUBTITLE_META_H__ */
|
1813
ext/ttml/ttmlparse.c
Normal file
1813
ext/ttml/ttmlparse.c
Normal file
File diff suppressed because it is too large
Load diff
34
ext/ttml/ttmlparse.h
Normal file
34
ext/ttml/ttmlparse.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* GStreamer TTML subtitle parser
|
||||
* Copyright (C) <2015> British Broadcasting Corporation
|
||||
* Authors:
|
||||
* Chris Bass <dash@rd.bbc.co.uk>
|
||||
* Peter Taylour <dash@rd.bbc.co.uk>
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef _TTML_PARSE_H_
|
||||
#define _TTML_PARSE_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GList *ttml_parse (const gchar * file, GstClockTime begin,
|
||||
GstClockTime duration);
|
||||
|
||||
G_END_DECLS
|
||||
#endif /* _TTML_PARSE_H_ */
|
Loading…
Reference in a new issue