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