2016-06-29 08:58:38 +00:00
|
|
|
/* 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
|
2017-03-08 18:01:13 +00:00
|
|
|
* @title: GstSubtitle
|
2016-06-29 08:58:38 +00:00
|
|
|
* @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"
|
|
|
|
|
2017-03-21 13:50:12 +00:00
|
|
|
/**
|
|
|
|
* gst_subtitle_style_set_free:
|
|
|
|
* @style_set: A #GstSubtitleStyleSet.
|
|
|
|
*
|
|
|
|
* Free @style_set and its associated memory.
|
|
|
|
*/
|
|
|
|
static 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleStyleSet, gst_subtitle_style_set);
|
|
|
|
|
2016-06-29 08:58:38 +00:00
|
|
|
/**
|
|
|
|
* 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 };
|
|
|
|
|
2017-03-21 13:50:12 +00:00
|
|
|
gst_mini_object_init (GST_MINI_OBJECT_CAST (ret), 0,
|
|
|
|
gst_subtitle_style_set_get_type (), NULL, NULL,
|
|
|
|
(GstMiniObjectFreeFunction) _gst_subtitle_style_set_free);
|
|
|
|
|
2016-06-29 08:58:38 +00:00
|
|
|
ret->font_family = g_strdup ("default");
|
|
|
|
ret->font_size = 1.0;
|
2017-03-22 10:21:28 +00:00
|
|
|
ret->line_height = -1;
|
2016-06-29 08:58:38 +00:00
|
|
|
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;
|
2018-02-27 10:07:18 +00:00
|
|
|
ret->fill_line_gap = FALSE;
|
2016-06-29 08:58:38 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
_gst_subtitle_element_free (GstSubtitleElement * element)
|
|
|
|
{
|
|
|
|
g_return_if_fail (element != NULL);
|
2017-03-21 13:50:12 +00:00
|
|
|
gst_subtitle_style_set_unref (element->style_set);
|
2016-06-29 08:58:38 +00:00
|
|
|
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);
|
2017-03-21 13:50:12 +00:00
|
|
|
gst_subtitle_style_set_unref (block->style_set);
|
2016-06-29 08:58:38 +00:00
|
|
|
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.
|
|
|
|
*/
|
2017-03-21 13:50:12 +00:00
|
|
|
GstSubtitleElement *
|
2016-06-29 08:58:38 +00:00
|
|
|
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);
|
2017-03-21 13:50:12 +00:00
|
|
|
gst_subtitle_style_set_unref (region->style_set);
|
2016-06-29 08:58:38 +00:00
|
|
|
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);
|
|
|
|
}
|