1 /* GStreamer
2  * Copyright (C) <2015> British Broadcasting Corporation
3  *   Author: Chris Bass <dash@rd.bbc.co.uk>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 /**
22  * SECTION:gstsubtitle
23  * @title: GstSubtitle
24  * @short_description: Library for describing sets of static subtitles.
25  *
26  * This library enables the description of static text scenes made up of a
27  * number of regions, which may contain a number of block and inline text
28  * elements. It is derived from the concepts and features defined in the Timed
29  * Text Markup Language 1 (TTML1), Second Edition
30  * (http://www.w3.org/TR/ttaf1-dfxp), and the EBU-TT-D profile of TTML1
31  * (https://tech.ebu.ch/files/live/sites/tech/files/shared/tech/tech3380.pdf).
32  */
33 
34 #include "subtitle.h"
35 
36 /**
37  * gst_subtitle_style_set_free:
38  * @style_set: A #GstSubtitleStyleSet.
39  *
40  * Free @style_set and its associated memory.
41  */
42 static void
_gst_subtitle_style_set_free(GstSubtitleStyleSet * style_set)43 _gst_subtitle_style_set_free (GstSubtitleStyleSet * style_set)
44 {
45   g_return_if_fail (style_set != NULL);
46   g_free (style_set->font_family);
47   g_slice_free (GstSubtitleStyleSet, style_set);
48 }
49 
50 GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleStyleSet, gst_subtitle_style_set);
51 
52 /**
53  * gst_subtitle_style_set_new:
54  *
55  * Create a new #GstSubtitleStyleSet with default values for all properties.
56  *
57  * Returns: (transfer full): A newly-allocated #GstSubtitleStyleSet.
58  */
59 GstSubtitleStyleSet *
gst_subtitle_style_set_new(void)60 gst_subtitle_style_set_new (void)
61 {
62   GstSubtitleStyleSet *ret = g_slice_new0 (GstSubtitleStyleSet);
63   GstSubtitleColor white = { 255, 255, 255, 255 };
64   GstSubtitleColor transparent = { 0, 0, 0, 0 };
65 
66   gst_mini_object_init (GST_MINI_OBJECT_CAST (ret), 0,
67       gst_subtitle_style_set_get_type (), NULL, NULL,
68       (GstMiniObjectFreeFunction) _gst_subtitle_style_set_free);
69 
70   ret->font_family = g_strdup ("default");
71   ret->font_size = 1.0;
72   ret->line_height = -1;
73   ret->color = white;
74   ret->background_color = transparent;
75   ret->line_padding = 0.0;
76   ret->origin_x = ret->origin_y = 0.0;
77   ret->extent_w = ret->extent_h = 0.0;
78   ret->padding_start = ret->padding_end
79       = ret->padding_before = ret->padding_after = 0.0;
80   ret->fill_line_gap = FALSE;
81 
82   return ret;
83 }
84 
85 
86 static void
_gst_subtitle_element_free(GstSubtitleElement * element)87 _gst_subtitle_element_free (GstSubtitleElement * element)
88 {
89   g_return_if_fail (element != NULL);
90   gst_subtitle_style_set_unref (element->style_set);
91   g_slice_free (GstSubtitleElement, element);
92 }
93 
94 GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleElement, gst_subtitle_element);
95 
96 /**
97  * gst_subtitle_element_new:
98  * @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
99  * and layout associated with this inline text element.
100  * @text_index: The index within a #GstBuffer of the #GstMemory that contains
101  * the text of this inline text element.
102  *
103  * Allocates a new #GstSubtitleElement.
104  *
105  * Returns: (transfer full): A newly-allocated #GstSubtitleElement. Unref
106  * with gst_subtitle_element_unref() when no longer needed.
107  */
108 GstSubtitleElement *
gst_subtitle_element_new(GstSubtitleStyleSet * style_set,guint text_index,gboolean suppress_whitespace)109 gst_subtitle_element_new (GstSubtitleStyleSet * style_set,
110     guint text_index, gboolean suppress_whitespace)
111 {
112   GstSubtitleElement *element;
113 
114   g_return_val_if_fail (style_set != NULL, NULL);
115 
116   element = g_slice_new0 (GstSubtitleElement);
117   gst_mini_object_init (GST_MINI_OBJECT_CAST (element), 0,
118       gst_subtitle_element_get_type (), NULL, NULL,
119       (GstMiniObjectFreeFunction) _gst_subtitle_element_free);
120 
121   element->style_set = style_set;
122   element->text_index = text_index;
123   element->suppress_whitespace = suppress_whitespace;
124 
125   return element;
126 }
127 
128 static void
_gst_subtitle_block_free(GstSubtitleBlock * block)129 _gst_subtitle_block_free (GstSubtitleBlock * block)
130 {
131   g_return_if_fail (block != NULL);
132   gst_subtitle_style_set_unref (block->style_set);
133   g_ptr_array_unref (block->elements);
134   g_slice_free (GstSubtitleBlock, block);
135 }
136 
137 GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleBlock, gst_subtitle_block);
138 
139 
140 /**
141  * gst_subtitle_block_new:
142  * @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
143  * and layout associated with this block of text elements.
144  *
145  * Allocates a new #GstSubtitleBlock.
146  *
147  * Returns: (transfer full): A newly-allocated #GstSubtitleBlock. Unref
148  * with gst_subtitle_block_unref() when no longer needed.
149  */
150 GstSubtitleBlock *
gst_subtitle_block_new(GstSubtitleStyleSet * style_set)151 gst_subtitle_block_new (GstSubtitleStyleSet * style_set)
152 {
153   GstSubtitleBlock *block;
154 
155   g_return_val_if_fail (style_set != NULL, NULL);
156 
157   block = g_slice_new0 (GstSubtitleBlock);
158   gst_mini_object_init (GST_MINI_OBJECT_CAST (block), 0,
159       gst_subtitle_block_get_type (), NULL, NULL,
160       (GstMiniObjectFreeFunction) _gst_subtitle_block_free);
161 
162   block->style_set = style_set;
163   block->elements = g_ptr_array_new_with_free_func (
164       (GDestroyNotify) gst_subtitle_element_unref);
165 
166   return block;
167 }
168 
169 /**
170  * gst_subtitle_block_add_element:
171  * @block: A #GstSubtitleBlock.
172  * @element: (transfer full): A #GstSubtitleElement to add.
173  *
174  * Adds a #GstSubtitleElement to @block.
175  */
176 void
gst_subtitle_block_add_element(GstSubtitleBlock * block,GstSubtitleElement * element)177 gst_subtitle_block_add_element (GstSubtitleBlock * block,
178     GstSubtitleElement * element)
179 {
180   g_return_if_fail (block != NULL);
181   g_return_if_fail (element != NULL);
182 
183   g_ptr_array_add (block->elements, element);
184 }
185 
186 /**
187  * gst_subtitle_block_get_element_count:
188  * @block: A #GstSubtitleBlock.
189  *
190  * Returns: The number of #GstSubtitleElements in @block.
191  */
192 guint
gst_subtitle_block_get_element_count(const GstSubtitleBlock * block)193 gst_subtitle_block_get_element_count (const GstSubtitleBlock * block)
194 {
195   g_return_val_if_fail (block != NULL, 0);
196 
197   return block->elements->len;
198 }
199 
200 /**
201  * gst_subtitle_block_get_element:
202  * @block: A #GstSubtitleBlock.
203  * @index: Index of the element to get.
204  *
205  * Gets the #GstSubtitleElement at @index in the array of elements held by
206  * @block.
207  *
208  * Returns: (transfer none): The #GstSubtitleElement at @index in the array of
209  * elements held by @block, or %NULL if @index is out-of-bounds. The
210  * function does not return a reference; the caller should obtain a reference
211  * using gst_subtitle_element_ref(), if needed.
212  */
213 GstSubtitleElement *
gst_subtitle_block_get_element(const GstSubtitleBlock * block,guint index)214 gst_subtitle_block_get_element (const GstSubtitleBlock * block, guint index)
215 {
216   g_return_val_if_fail (block != NULL, NULL);
217 
218   if (index >= block->elements->len)
219     return NULL;
220   else
221     return g_ptr_array_index (block->elements, index);
222 }
223 
224 static void
_gst_subtitle_region_free(GstSubtitleRegion * region)225 _gst_subtitle_region_free (GstSubtitleRegion * region)
226 {
227   g_return_if_fail (region != NULL);
228   gst_subtitle_style_set_unref (region->style_set);
229   g_ptr_array_unref (region->blocks);
230   g_slice_free (GstSubtitleRegion, region);
231 }
232 
233 GST_DEFINE_MINI_OBJECT_TYPE (GstSubtitleRegion, gst_subtitle_region);
234 
235 
236 /**
237  * gst_subtitle_region_new:
238  * @style_set: (transfer full): A #GstSubtitleStyleSet that defines the styling
239  * and layout associated with this region.
240  *
241  * Allocates a new #GstSubtitleRegion.
242  *
243  * Returns: (transfer full): A newly-allocated #GstSubtitleRegion. Unref
244  * with gst_subtitle_region_unref() when no longer needed.
245  */
246 GstSubtitleRegion *
gst_subtitle_region_new(GstSubtitleStyleSet * style_set)247 gst_subtitle_region_new (GstSubtitleStyleSet * style_set)
248 {
249   GstSubtitleRegion *region;
250 
251   g_return_val_if_fail (style_set != NULL, NULL);
252 
253   region = g_slice_new0 (GstSubtitleRegion);
254   gst_mini_object_init (GST_MINI_OBJECT_CAST (region), 0,
255       gst_subtitle_region_get_type (), NULL, NULL,
256       (GstMiniObjectFreeFunction) _gst_subtitle_region_free);
257 
258   region->style_set = style_set;
259   region->blocks = g_ptr_array_new_with_free_func (
260       (GDestroyNotify) gst_subtitle_block_unref);
261 
262   return region;
263 }
264 
265 /**
266  * gst_subtitle_region_add_block:
267  * @region: A #GstSubtitleRegion.
268  * @block: (transfer full): A #GstSubtitleBlock which should be added
269  * to @region's array of blocks.
270  *
271  * Adds a #GstSubtitleBlock to the end of the array of blocks held by @region.
272  * @region will take ownership of @block, and will unref it when @region
273  * is freed.
274  */
275 void
gst_subtitle_region_add_block(GstSubtitleRegion * region,GstSubtitleBlock * block)276 gst_subtitle_region_add_block (GstSubtitleRegion * region,
277     GstSubtitleBlock * block)
278 {
279   g_return_if_fail (region != NULL);
280   g_return_if_fail (block != NULL);
281 
282   g_ptr_array_add (region->blocks, block);
283 }
284 
285 /**
286  * gst_subtitle_region_get_block_count:
287  * @region: A #GstSubtitleRegion.
288  *
289  * Returns: The number of blocks in @region.
290  */
291 guint
gst_subtitle_region_get_block_count(const GstSubtitleRegion * region)292 gst_subtitle_region_get_block_count (const GstSubtitleRegion * region)
293 {
294   g_return_val_if_fail (region != NULL, 0);
295 
296   return region->blocks->len;
297 }
298 
299 /**
300  * gst_subtitle_region_get_block:
301  * @region: A #GstSubtitleRegion.
302  * @index: Index of the block to get.
303  *
304  * Gets the block at @index in the array of blocks held by @region.
305  *
306  * Returns: (transfer none): The #GstSubtitleBlock at @index in the array of
307  * blocks held by @region, or %NULL if @index is out-of-bounds. The
308  * function does not return a reference; the caller should obtain a reference
309  * using gst_subtitle_block_ref(), if needed.
310  */
311 const GstSubtitleBlock *
gst_subtitle_region_get_block(const GstSubtitleRegion * region,guint index)312 gst_subtitle_region_get_block (const GstSubtitleRegion * region, guint index)
313 {
314   g_return_val_if_fail (region != NULL, NULL);
315 
316   if (index >= region->blocks->len)
317     return NULL;
318   else
319     return g_ptr_array_index (region->blocks, index);
320 }
321