1 /*
2 * GStreamer
3 * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
4 * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
5 * Copyright 2008 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 * DEALINGS IN THE SOFTWARE.
24 *
25 * Alternatively, the contents of this file may be used under the
26 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
27 * which case the following provisions apply instead of the ones
28 * mentioned above:
29 *
30 * This library is free software; you can redistribute it and/or
31 * modify it under the terms of the GNU Library General Public
32 * License as published by the Free Software Foundation; either
33 * version 2 of the License, or (at your option) any later version.
34 *
35 * This library is distributed in the hope that it will be useful,
36 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38 * Library General Public License for more details.
39 *
40 * You should have received a copy of the GNU Library General Public
41 * License along with this library; if not, write to the
42 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
43 * Boston, MA 02110-1301, USA.
44 */
45
46 /**
47 * SECTION:element-tiger
48 * @title: tiger
49 * @see_also: katedec
50 *
51 * This element decodes and renders Kate streams.
52 * [Kate](http://libkate.googlecode.com/) is a free codec for text based data,
53 * such as subtitles. Any number of kate streams can be embedded in an Ogg
54 * stream.
55 *
56 * libkate (see above url) and [libtiger](http://libtiger.googlecode.com/)
57 * are needed to build this element.
58 *
59 * ## Example pipeline
60 *
61 * This pipeline renders a Kate stream on top of a Theora video multiplexed
62 * in the same stream:
63 * |[
64 * gst-launch-1.0 \
65 * filesrc location=video.ogg ! oggdemux name=demux \
66 * demux. ! queue ! theoradec ! videoconvert ! tiger name=tiger \
67 * demux. ! queue ! kateparse ! tiger. \
68 * tiger. ! videoconvert ! autovideosink
69 * ]|
70 *
71 */
72
73 #ifdef HAVE_CONFIG_H
74 #include "config.h"
75 #endif
76
77 #include <string.h>
78
79 #include <gst/gst.h>
80 #include <gst/glib-compat-private.h>
81 #include <gst/video/video.h>
82
83 #include "gstkateelements.h"
84 #include "gstkatetiger.h"
85
86 GST_DEBUG_CATEGORY_EXTERN (gst_katetiger_debug);
87 #define GST_CAT_DEFAULT gst_katetiger_debug
88
89 #define GST_KATE_TIGER_MUTEX_LOCK(element) \
90 do { \
91 /*GST_LOG_OBJECT ((element), "locking from %s:%d",__FILE__,__LINE__);*/ \
92 g_mutex_lock ((element)->mutex); \
93 /*GST_LOG_OBJECT ((element), "ready from %s:%d",__FILE__,__LINE__);*/ \
94 } while(0)
95
96 #define GST_KATE_TIGER_MUTEX_UNLOCK(element) \
97 do { \
98 /*GST_LOG_OBJECT ((element), "unlocking from %s:%d",__FILE__,__LINE__);*/ \
99 g_mutex_unlock ((element)->mutex); \
100 } while(0)
101
102 /* Filter signals and args */
103 enum
104 {
105 /* FILL ME */
106 LAST_SIGNAL
107 };
108
109 enum
110 {
111 ARG_DEFAULT_FONT_DESC = DECODER_BASE_ARG_COUNT,
112 ARG_QUALITY,
113 ARG_DEFAULT_FONT_EFFECT,
114 ARG_DEFAULT_FONT_EFFECT_STRENGTH,
115 ARG_DEFAULT_FONT_RED,
116 ARG_DEFAULT_FONT_GREEN,
117 ARG_DEFAULT_FONT_BLUE,
118 ARG_DEFAULT_FONT_ALPHA,
119 ARG_DEFAULT_BACKGROUND_RED,
120 ARG_DEFAULT_BACKGROUND_GREEN,
121 ARG_DEFAULT_BACKGROUND_BLUE,
122 ARG_DEFAULT_BACKGROUND_ALPHA,
123 ARG_SILENT
124 };
125
126 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
127 # define TIGER_ARGB_A 3
128 # define TIGER_ARGB_R 2
129 # define TIGER_ARGB_G 1
130 # define TIGER_ARGB_B 0
131 #else
132 # define TIGER_ARGB_A 0
133 # define TIGER_ARGB_R 1
134 # define TIGER_ARGB_G 2
135 # define TIGER_ARGB_B 3
136 #endif
137
138 #define TIGER_UNPREMULTIPLY(a,r,g,b) G_STMT_START { \
139 b = (a > 0) ? MIN ((b * 255 + a / 2) / a, 255) : 0; \
140 g = (a > 0) ? MIN ((g * 255 + a / 2) / a, 255) : 0; \
141 r = (a > 0) ? MIN ((r * 255 + a / 2) / a, 255) : 0; \
142 } G_STMT_END
143
144 static GstStaticPadTemplate kate_sink_factory =
145 GST_STATIC_PAD_TEMPLATE ("subtitle_sink",
146 GST_PAD_SINK,
147 GST_PAD_ALWAYS,
148 GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate")
149 );
150
151 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
152 #define TIGER_VIDEO_CAPS \
153 GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";" \
154 GST_VIDEO_CAPS_YUV ("{I420, YV12, AYUV, YUY2, UYVY, v308, v210," \
155 " v216, Y41B, Y42B, Y444, Y800, Y16, NV12, NV21, UYVP, A420," \
156 " YUV9, IYU1}")
157
158 #else
159 #define TIGER_VIDEO_CAPS \
160 GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xRGB ";" \
161 GST_VIDEO_CAPS_YUV ("{I420, YV12, AYUV, YUY2, UYVY, v308, v210," \
162 " v216, Y41B, Y42B, Y444, Y800, Y16, NV12, NV21, UYVP, A420," \
163 " YUV9, IYU1}")
164 #endif
165
166 static GstStaticPadTemplate video_sink_factory =
167 GST_STATIC_PAD_TEMPLATE ("video_sink",
168 GST_PAD_SINK,
169 GST_PAD_ALWAYS,
170 GST_STATIC_CAPS (TIGER_VIDEO_CAPS));
171
172 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
173 GST_PAD_SRC,
174 GST_PAD_ALWAYS,
175 GST_STATIC_CAPS (TIGER_VIDEO_CAPS));
176
177 GST_DEBUG_CATEGORY (gst_katetiger_debug);
178
179 GST_BOILERPLATE (GstKateTiger, gst_kate_tiger, GstElement, GST_TYPE_ELEMENT);
180 #define _do_init \
181 kate_element_init (plugin); \
182 GST_DEBUG_CATEGORY_INIT (gst_katetiger_debug, "tiger", 0, \
183 "Kate Tiger renderer");
184 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (tiger, "tiger", GST_RANK_NONE,
185 GST_TYPE_KATE_TIGER, _do_init);
186
187 static GType
gst_kate_tiger_font_effect_get_type(void)188 gst_kate_tiger_font_effect_get_type (void)
189 {
190 static GType font_effect_type = 0;
191
192 if (!font_effect_type) {
193 static const GEnumValue font_effects[] = {
194 {tiger_font_plain, "none", "none"},
195 {tiger_font_shadow, "shadow", "shadow"},
196 {tiger_font_outline, "outline", "outline"},
197 {0, NULL, NULL}
198 };
199 font_effect_type = g_enum_register_static ("GstFontEffect", font_effects);
200 }
201
202 return font_effect_type;
203 }
204
205 static void gst_kate_tiger_set_property (GObject * object, guint prop_id,
206 const GValue * value, GParamSpec * pspec);
207 static void gst_kate_tiger_get_property (GObject * object, guint prop_id,
208 GValue * value, GParamSpec * pspec);
209 static void gst_kate_tiger_dispose (GObject * object);
210
211 static GstFlowReturn gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf);
212 static GstFlowReturn gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf);
213 static GstStateChangeReturn gst_kate_tiger_change_state (GstElement * element,
214 GstStateChange transition);
215 static gboolean gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query);
216 static gboolean gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event);
217 static gboolean gst_kate_tiger_video_event (GstPad * pad, GstEvent * event);
218 static gboolean gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps);
219 static gboolean gst_kate_tiger_source_event (GstPad * pad, GstEvent * event);
220
221 static void
gst_kate_tiger_base_init(gpointer gclass)222 gst_kate_tiger_base_init (gpointer gclass)
223 {
224
225 GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
226
227 gst_element_class_add_static_pad_template (element_class, &src_factory);
228 gst_element_class_add_static_pad_template (element_class, &kate_sink_factory);
229 gst_element_class_add_static_pad_template (element_class,
230 &video_sink_factory);
231 gst_element_class_set_static_metadata (element_class, "Kate stream renderer",
232 "Mixer/Video/Overlay/Subtitle",
233 "Decodes and renders Kate streams on top of a video",
234 "Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
235 }
236
237 /* initialize the plugin's class */
238 static void
gst_kate_tiger_class_init(GstKateTigerClass * klass)239 gst_kate_tiger_class_init (GstKateTigerClass * klass)
240 {
241 GObjectClass *gobject_class;
242 GstElementClass *gstelement_class;
243
244 gobject_class = (GObjectClass *) klass;
245 gstelement_class = (GstElementClass *) klass;
246
247 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_tiger_get_property);
248 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_tiger_set_property);
249 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_kate_tiger_dispose);
250
251 gst_kate_util_install_decoder_base_properties (gobject_class);
252
253 g_object_class_install_property (gobject_class, ARG_QUALITY,
254 g_param_spec_double ("quality", "Rendering quality",
255 "Rendering quality (0 is faster, 1 is best and slower)",
256 0.0, 1.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
257
258 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_DESC,
259 g_param_spec_string ("default-font-desc", "Default font description",
260 "Default font description (Pango style) to render text with",
261 "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
262
263 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_EFFECT,
264 g_param_spec_enum ("default-font-effect", "Default font effect",
265 "Whether to apply an effect to text by default, for increased readability",
266 gst_kate_tiger_font_effect_get_type (),
267 tiger_font_outline,
268 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
269
270 g_object_class_install_property (gobject_class,
271 ARG_DEFAULT_FONT_EFFECT_STRENGTH,
272 g_param_spec_double ("default-font-effect-strength",
273 "Default font effect strength",
274 "How pronounced should the font effect be (effect dependent)", 0.0,
275 1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276
277 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_RED,
278 g_param_spec_int ("default-font-red",
279 "Default font color (red component)",
280 "Default font color (red component, between 0 and 255) to render text with",
281 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
282
283 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_GREEN,
284 g_param_spec_int ("default-font-green",
285 "Default font color (green component)",
286 "Default font color (green component, between 0 and 255) to render text with",
287 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
288
289 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_BLUE,
290 g_param_spec_int ("default-font-blue",
291 "Default font color (blue component)",
292 "Default font color (blue component, between 0 and 255) to render text with",
293 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294
295 g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_ALPHA,
296 g_param_spec_int ("default-font-alpha",
297 "Default font color (alpha component)",
298 "Default font color (alpha component, between 0 and 255) to render text with",
299 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
300
301 g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_RED,
302 g_param_spec_int ("default-background-red",
303 "Default background color (red component)",
304 "Default background color (red component, between 0 and 255) to render text with",
305 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
306
307 g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_GREEN,
308 g_param_spec_int ("default-background-green",
309 "Default background color (green component)",
310 "Default background color (green component, between 0 and 255) to render text with",
311 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
312
313 g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_BLUE,
314 g_param_spec_int ("default-background-blue",
315 "Default background color (blue component)",
316 "Default background color (blue component, between 0 and 255) to render text with",
317 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
318
319 g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_ALPHA,
320 g_param_spec_int ("default-background-alpha",
321 "Default background color (alpha component)",
322 "Default background color (alpha component, between 0 and 255) to render text with",
323 0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
324
325 /* FIXME 0.11: rename to "visible" or "text-visible" or "render-text" */
326 g_object_class_install_property (gobject_class, ARG_SILENT,
327 g_param_spec_boolean ("silent", "silent",
328 "Whether to render the stream",
329 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
330
331 gstelement_class->change_state =
332 GST_DEBUG_FUNCPTR (gst_kate_tiger_change_state);
333 }
334
335 /* initialize the new element
336 * instantiate pads and add them to element
337 * set functions
338 * initialize structure
339 */
340 static void
gst_kate_tiger_init(GstKateTiger * tiger,GstKateTigerClass * gclass)341 gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass)
342 {
343 GST_DEBUG_OBJECT (tiger, "gst_kate_tiger_init");
344
345 tiger->mutex = g_mutex_new ();
346 tiger->cond = g_cond_new ();
347
348 tiger->katesinkpad =
349 gst_pad_new_from_static_template (&kate_sink_factory, "subtitle_sink");
350 gst_pad_set_chain_function (tiger->katesinkpad,
351 GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_chain));
352 gst_pad_set_query_function (tiger->katesinkpad,
353 GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_sink_query));
354 gst_pad_set_event_function (tiger->katesinkpad,
355 GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_event));
356 gst_element_add_pad (GST_ELEMENT (tiger), tiger->katesinkpad);
357
358 tiger->videosinkpad =
359 gst_pad_new_from_static_template (&video_sink_factory, "video_sink");
360 gst_pad_set_chain_function (tiger->videosinkpad,
361 GST_DEBUG_FUNCPTR (gst_kate_tiger_video_chain));
362 gst_pad_use_fixed_caps (tiger->videosinkpad);
363 gst_pad_set_setcaps_function (tiger->videosinkpad,
364 GST_DEBUG_FUNCPTR (gst_kate_tiger_video_set_caps));
365 gst_pad_set_event_function (tiger->videosinkpad,
366 GST_DEBUG_FUNCPTR (gst_kate_tiger_video_event));
367 gst_element_add_pad (GST_ELEMENT (tiger), tiger->videosinkpad);
368
369 tiger->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
370 gst_pad_set_event_function (tiger->srcpad, gst_kate_tiger_source_event);
371 gst_pad_use_fixed_caps (tiger->srcpad);
372 gst_element_add_pad (GST_ELEMENT (tiger), tiger->srcpad);
373
374 gst_kate_util_decode_base_init (&tiger->decoder, FALSE);
375
376 tiger->tr = NULL;
377
378 tiger->default_font_desc = NULL;
379 tiger->quality = -1.0;
380 tiger->default_font_effect = tiger_font_outline;
381 tiger->default_font_effect_strength = 0.5;
382 tiger->default_font_r = 255;
383 tiger->default_font_g = 255;
384 tiger->default_font_b = 255;
385 tiger->default_font_a = 255;
386 tiger->default_background_r = 0;
387 tiger->default_background_g = 0;
388 tiger->default_background_b = 0;
389 tiger->default_background_a = 0;
390 tiger->silent = FALSE;
391
392 tiger->video_width = 0;
393 tiger->video_height = 0;
394
395 tiger->composition = NULL;
396
397 tiger->seen_header = FALSE;
398 }
399
400 static void
gst_kate_tiger_dispose(GObject * object)401 gst_kate_tiger_dispose (GObject * object)
402 {
403 GstKateTiger *tiger = GST_KATE_TIGER (object);
404
405 GST_LOG_OBJECT (tiger, "disposing");
406
407 if (tiger->default_font_desc) {
408 g_free (tiger->default_font_desc);
409 tiger->default_font_desc = NULL;
410 }
411
412 if (tiger->render_buffer) {
413 gst_buffer_unref (tiger->render_buffer);
414 tiger->render_buffer = NULL;
415 }
416
417 g_cond_free (tiger->cond);
418 tiger->cond = NULL;
419
420 g_mutex_free (tiger->mutex);
421 tiger->mutex = NULL;
422
423 if (tiger->composition) {
424 gst_video_overlay_composition_unref (tiger->composition);
425 tiger->composition = NULL;
426 }
427
428 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
429 }
430
431 static void
gst_kate_tiger_update_quality(GstKateTiger * tiger)432 gst_kate_tiger_update_quality (GstKateTiger * tiger)
433 {
434 if (tiger->tr && tiger->quality >= 0.0) {
435 tiger_renderer_set_quality (tiger->tr, tiger->quality);
436 }
437 }
438
439 static void
gst_kate_tiger_update_default_font_effect(GstKateTiger * tiger)440 gst_kate_tiger_update_default_font_effect (GstKateTiger * tiger)
441 {
442 if (tiger->tr) {
443 tiger_renderer_set_default_font_effect (tiger->tr,
444 tiger->default_font_effect, tiger->default_font_effect_strength);
445 }
446 }
447
448 static void
gst_kate_tiger_update_default_font_color(GstKateTiger * tiger)449 gst_kate_tiger_update_default_font_color (GstKateTiger * tiger)
450 {
451 if (tiger->tr) {
452 tiger_renderer_set_default_font_color (tiger->tr,
453 tiger->default_font_r / 255.0,
454 tiger->default_font_g / 255.0,
455 tiger->default_font_b / 255.0, tiger->default_font_a / 255.0);
456 }
457 }
458
459 static void
gst_kate_tiger_update_default_background_color(GstKateTiger * tiger)460 gst_kate_tiger_update_default_background_color (GstKateTiger * tiger)
461 {
462 if (tiger->tr) {
463 tiger_renderer_set_default_background_fill_color (tiger->tr,
464 tiger->default_background_r / 255.0,
465 tiger->default_background_g / 255.0,
466 tiger->default_background_b / 255.0,
467 tiger->default_background_a / 255.0);
468 }
469 }
470
471 static void
gst_kate_tiger_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)472 gst_kate_tiger_set_property (GObject * object, guint prop_id,
473 const GValue * value, GParamSpec * pspec)
474 {
475 GstKateTiger *tiger = GST_KATE_TIGER (object);
476 const char *str;
477
478 GST_KATE_TIGER_MUTEX_LOCK (tiger);
479
480 switch (prop_id) {
481 case ARG_DEFAULT_FONT_DESC:
482 if (tiger->default_font_desc) {
483 g_free (tiger->default_font_desc);
484 tiger->default_font_desc = NULL;
485 }
486 str = g_value_get_string (value);
487 if (str) {
488 tiger->default_font_desc = g_strdup (str);
489 if (tiger->tr)
490 tiger_renderer_set_default_font_description (tiger->tr,
491 tiger->default_font_desc);
492 }
493 break;
494 case ARG_QUALITY:
495 tiger->quality = g_value_get_double (value);
496 gst_kate_tiger_update_quality (tiger);
497 break;
498 case ARG_DEFAULT_FONT_EFFECT:
499 tiger->default_font_effect = g_value_get_enum (value);
500 gst_kate_tiger_update_default_font_effect (tiger);
501 break;
502 case ARG_DEFAULT_FONT_EFFECT_STRENGTH:
503 tiger->default_font_effect_strength = g_value_get_double (value);
504 gst_kate_tiger_update_default_font_effect (tiger);
505 break;
506 case ARG_DEFAULT_FONT_RED:
507 tiger->default_font_r = g_value_get_int (value);
508 gst_kate_tiger_update_default_font_color (tiger);
509 break;
510 case ARG_DEFAULT_FONT_GREEN:
511 tiger->default_font_g = g_value_get_int (value);
512 gst_kate_tiger_update_default_font_color (tiger);
513 break;
514 case ARG_DEFAULT_FONT_BLUE:
515 tiger->default_font_b = g_value_get_int (value);
516 gst_kate_tiger_update_default_font_color (tiger);
517 break;
518 case ARG_DEFAULT_FONT_ALPHA:
519 tiger->default_font_a = g_value_get_int (value);
520 gst_kate_tiger_update_default_font_color (tiger);
521 break;
522 case ARG_DEFAULT_BACKGROUND_RED:
523 tiger->default_background_r = g_value_get_int (value);
524 gst_kate_tiger_update_default_background_color (tiger);
525 break;
526 case ARG_DEFAULT_BACKGROUND_GREEN:
527 tiger->default_background_g = g_value_get_int (value);
528 gst_kate_tiger_update_default_background_color (tiger);
529 break;
530 case ARG_DEFAULT_BACKGROUND_BLUE:
531 tiger->default_background_b = g_value_get_int (value);
532 gst_kate_tiger_update_default_background_color (tiger);
533 break;
534 case ARG_DEFAULT_BACKGROUND_ALPHA:
535 tiger->default_background_a = g_value_get_int (value);
536 gst_kate_tiger_update_default_background_color (tiger);
537 break;
538 case ARG_SILENT:
539 tiger->silent = g_value_get_boolean (value);
540 break;
541 default:
542 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
543 break;
544 }
545
546 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
547 }
548
549 static void
gst_kate_tiger_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)550 gst_kate_tiger_get_property (GObject * object, guint prop_id,
551 GValue * value, GParamSpec * pspec)
552 {
553 GstKateTiger *tiger = GST_KATE_TIGER (object);
554
555 GST_KATE_TIGER_MUTEX_LOCK (tiger);
556
557 switch (prop_id) {
558 case ARG_DEFAULT_FONT_DESC:
559 g_value_set_string (value,
560 tiger->default_font_desc ? tiger->default_font_desc : "");
561 break;
562 case ARG_QUALITY:
563 g_value_set_double (value, tiger->quality);
564 break;
565 case ARG_DEFAULT_FONT_EFFECT:
566 g_value_set_enum (value, tiger->default_font_effect);
567 break;
568 case ARG_DEFAULT_FONT_EFFECT_STRENGTH:
569 g_value_set_double (value, tiger->default_font_effect_strength);
570 break;
571 case ARG_DEFAULT_FONT_RED:
572 g_value_set_int (value, tiger->default_font_r);
573 break;
574 case ARG_DEFAULT_FONT_GREEN:
575 g_value_set_int (value, tiger->default_font_g);
576 break;
577 case ARG_DEFAULT_FONT_BLUE:
578 g_value_set_int (value, tiger->default_font_b);
579 break;
580 case ARG_DEFAULT_FONT_ALPHA:
581 g_value_set_int (value, tiger->default_font_a);
582 break;
583 case ARG_DEFAULT_BACKGROUND_RED:
584 g_value_set_int (value, tiger->default_background_r);
585 break;
586 case ARG_DEFAULT_BACKGROUND_GREEN:
587 g_value_set_int (value, tiger->default_background_g);
588 break;
589 case ARG_DEFAULT_BACKGROUND_BLUE:
590 g_value_set_int (value, tiger->default_background_b);
591 break;
592 case ARG_DEFAULT_BACKGROUND_ALPHA:
593 g_value_set_int (value, tiger->default_background_a);
594 break;
595 case ARG_SILENT:
596 g_value_set_boolean (value, tiger->silent);
597 break;
598 default:
599 if (!gst_kate_util_decoder_base_get_property (&tiger->decoder, object,
600 prop_id, value, pspec)) {
601 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
602 }
603 break;
604 }
605
606 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
607 }
608
609 /* GstElement vmethod implementations */
610
611 /* chain function
612 * this function does the actual processing
613 */
614
615 static GstFlowReturn
gst_kate_tiger_kate_chain(GstPad * pad,GstBuffer * buf)616 gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf)
617 {
618 GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
619 const kate_event *ev = NULL;
620 GstFlowReturn rflow = GST_FLOW_OK;
621
622 GST_KATE_TIGER_MUTEX_LOCK (tiger);
623
624 GST_LOG_OBJECT (tiger, "Got kate buffer, caps %" GST_PTR_FORMAT,
625 GST_BUFFER_CAPS (buf));
626
627 /* Now that we have the lock, check if we're flushing */
628 if (tiger->decoder.kate_flushing) {
629 GST_DEBUG_OBJECT (tiger, "Flushing, disregarding buffer");
630 goto done;
631 }
632
633 /* Unfortunately, it can happen that the start of the stream is not sent,
634 for instance if there's a stream selector upstream, which is switched
635 from another Kate stream. If this happens, then we can fallback on the
636 headers stored in the caps (if any). */
637 if (!tiger->seen_header) {
638 if (GST_BUFFER_SIZE (buf) == 0 || (GST_BUFFER_DATA (buf)[0] & 0x80) == 0) {
639 /* Not a header, try to fall back on caps */
640 GstStructure *s;
641 const GValue *streamheader;
642
643 GST_INFO_OBJECT (tiger, "Headers not seen, start of stream is cut off");
644 s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
645 streamheader = gst_structure_get_value (s, "streamheader");
646 if (streamheader && G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) {
647 GstPad *tagpad = gst_pad_get_peer (pad);
648 GArray *array;
649 gint i;
650
651 GST_INFO_OBJECT (tiger, "Falling back on caps to initialize decoder");
652 array = g_value_peek_pointer (streamheader);
653 for (i = 0; i < array->len; i++) {
654 GValue *value = &g_array_index (array, GValue, i);
655 if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) {
656 GstBuffer *hbuf = g_value_peek_pointer (value);
657 gst_buffer_ref (hbuf);
658 rflow =
659 gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder,
660 GST_ELEMENT_CAST (tiger), pad, hbuf, tiger->srcpad, tagpad,
661 NULL, NULL);
662 } else {
663 GST_WARNING_OBJECT (tiger,
664 "Streamheader index %d does not hold a buffer", i);
665 }
666 }
667 gst_object_unref (tagpad);
668 tiger->seen_header = TRUE;
669 } else {
670 GST_WARNING_OBJECT (tiger, "No headers seen, and no headers on caps");
671 }
672 } else {
673 tiger->seen_header = TRUE;
674 }
675 }
676
677 if (gst_kate_util_decoder_base_update_segment (&tiger->decoder,
678 GST_ELEMENT_CAST (tiger), buf)) {
679 GstPad *tagpad = gst_pad_get_peer (pad);
680 rflow =
681 gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder,
682 GST_ELEMENT_CAST (tiger), pad, buf, tiger->srcpad, tagpad, NULL, &ev);
683 if (G_LIKELY (rflow == GST_FLOW_OK)) {
684 if (ev) {
685 int ret = tiger_renderer_add_event (tiger->tr, ev->ki, ev);
686 GST_INFO_OBJECT (tiger, "adding event for %p from %f to %f: %p, \"%s\"",
687 ev->ki, ev->start_time, ev->end_time, ev->bitmap, ev->text);
688 if (G_UNLIKELY (ret < 0)) {
689 GST_WARNING_OBJECT (tiger,
690 "failed to add Kate event to Tiger renderer: %s",
691 gst_kate_util_get_error_message (ret));
692 }
693 }
694 }
695 gst_object_unref (tagpad);
696 }
697
698 /* we want to avoid shooting ahead of the video stream, or we will
699 get segment updates which will place us ahead of it, and we won't
700 be able to convert a video timestamp back into a kate timestamp */
701 if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
702 while (1) {
703 gint64 kate_time, video_time;
704 kate_time =
705 gst_segment_to_running_time (&tiger->decoder.kate_segment,
706 GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
707 video_time =
708 gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME,
709 tiger->video_segment.last_stop);
710 GST_DEBUG_OBJECT (tiger, "Kate time %.2f, video time %.2f (kts %ld)",
711 kate_time / (float) GST_SECOND, video_time / (float) GST_SECOND,
712 (long) GST_BUFFER_TIMESTAMP (buf));
713 if (kate_time <= video_time) {
714 break;
715 }
716 GST_LOG_OBJECT (tiger, "Waiting to return from chain function");
717 g_cond_wait (tiger->cond, tiger->mutex);
718 if (tiger->decoder.kate_flushing) {
719 GST_DEBUG_OBJECT (tiger, "Flushing while waiting");
720 break;
721 }
722 GST_LOG_OBJECT (tiger, "Woken up, checking time again");
723 }
724 }
725
726 done:
727 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
728
729 gst_object_unref (tiger);
730 gst_buffer_unref (buf);
731
732 return rflow;
733 }
734
735 static gboolean
gst_kate_tiger_video_set_caps(GstPad * pad,GstCaps * caps)736 gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps)
737 {
738 GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
739 GstVideoFormat format;
740 gint w, h;
741 gboolean ret;
742
743 GST_KATE_TIGER_MUTEX_LOCK (tiger);
744
745 /* Cairo expects ARGB in native endianness, and that's what we get
746 as we've forced it in the caps. We might allow swapped red/blue
747 at some point, and get tiger to swap, to make some cases faster */
748 tiger->swap_rgb = FALSE;
749
750 if (gst_video_format_parse_caps (caps, &format, &w, &h)) {
751 tiger->video_format = format;
752 tiger->video_width = w;
753 tiger->video_height = h;
754 }
755
756 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
757
758 ret = gst_pad_set_caps (tiger->srcpad, caps);
759
760 gst_object_unref (tiger);
761 return ret;
762 }
763
764 static gdouble
gst_kate_tiger_get_time(GstKateTiger * tiger)765 gst_kate_tiger_get_time (GstKateTiger * tiger)
766 {
767 gint64 rt =
768 gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME,
769 tiger->video_segment.last_stop);
770 gint64 pos =
771 gst_segment_to_position (&tiger->decoder.kate_segment, GST_FORMAT_TIME,
772 rt);
773 return pos / (gdouble) GST_SECOND;
774 }
775
776 static inline void
gst_kate_tiger_set_composition(GstKateTiger * tiger)777 gst_kate_tiger_set_composition (GstKateTiger * tiger)
778 {
779 GstVideoOverlayRectangle *rectangle;
780
781 if (tiger->render_buffer) {
782 rectangle = gst_video_overlay_rectangle_new_argb (tiger->render_buffer,
783 tiger->video_width, tiger->video_height, 4 * tiger->video_width,
784 0, 0, tiger->video_width, tiger->video_height,
785 GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA);
786
787 if (tiger->composition)
788 gst_video_overlay_composition_unref (tiger->composition);
789 tiger->composition = gst_video_overlay_composition_new (rectangle);
790 gst_video_overlay_rectangle_unref (rectangle);
791
792 } else if (tiger->composition) {
793 gst_video_overlay_composition_unref (tiger->composition);
794 tiger->composition = NULL;
795 }
796 }
797
798 static GstFlowReturn
gst_kate_tiger_video_chain(GstPad * pad,GstBuffer * buf)799 gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
800 {
801 GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
802 GstFlowReturn rflow = GST_FLOW_OK;
803 unsigned char *ptr;
804 int ret;
805 kate_float t;
806
807 GST_KATE_TIGER_MUTEX_LOCK (tiger);
808
809 GST_LOG_OBJECT (tiger, "got video frame, %u bytes", GST_BUFFER_SIZE (buf));
810
811 if (G_UNLIKELY (tiger->video_flushing)) {
812 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
813 gst_object_unref (tiger);
814 gst_buffer_unref (buf);
815 return GST_FLOW_FLUSHING;
816 }
817
818 if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
819 gst_segment_set_last_stop (&tiger->video_segment, GST_FORMAT_TIME,
820 GST_BUFFER_TIMESTAMP (buf));
821 g_cond_broadcast (tiger->cond);
822 }
823
824 /* Update first with a dummy buffer pointer we cannot write to, but with the
825 right dimensions. If there is nothing to draw, we will not have to make
826 it writeable. */
827 ptr = GST_BUFFER_DATA (buf);
828 ret =
829 tiger_renderer_set_buffer (tiger->tr, ptr, tiger->video_width,
830 tiger->video_height, tiger->video_width * 4, tiger->swap_rgb);
831 if (G_UNLIKELY (ret < 0)) {
832 GST_WARNING_OBJECT (tiger,
833 "Tiger renderer failed to set buffer to video frame: %s",
834 gst_kate_util_get_error_message (ret));
835 goto pass;
836 }
837
838 /* update the renderer at the time of the video frame */
839 t = gst_kate_tiger_get_time (tiger);
840 GST_LOG_OBJECT (tiger, "Video segment calc: last stop %ld, time %.3f",
841 (long) tiger->video_segment.last_stop, t);
842 ret = tiger_renderer_update (tiger->tr, t, 1);
843 if (G_UNLIKELY (ret < 0)) {
844 GST_WARNING_OBJECT (tiger, "Tiger renderer failed to update: %s",
845 gst_kate_util_get_error_message (ret));
846 goto pass;
847 }
848
849 /* if there nothing to draw, we can just push the video buffer as is */
850 if (ret > 0 || tiger->silent)
851 goto pass;
852
853 /* there is something to draw, so first make the buffer writable */
854 buf = gst_buffer_make_writable (buf);
855 if (G_UNLIKELY (!buf)) {
856 GST_WARNING_OBJECT (tiger, "Failed to make video buffer writable");
857 goto pass;
858 }
859
860 /* and setup that buffer before rendering */
861 if (gst_video_format_is_yuv (tiger->video_format)) {
862 if (!tiger->render_buffer) {
863 tiger->render_buffer =
864 gst_buffer_new_and_alloc (tiger->video_width * tiger->video_height *
865 4);
866 }
867 ptr = GST_BUFFER_DATA (tiger->render_buffer);
868 tiger_renderer_set_surface_clear_color (tiger->tr, 1, 0.0, 0.0, 0.0, 0.0);
869 } else {
870 ptr = GST_BUFFER_DATA (buf);
871 }
872 ret =
873 tiger_renderer_set_buffer (tiger->tr, ptr, tiger->video_width,
874 tiger->video_height, tiger->video_width * 4, tiger->swap_rgb);
875 if (G_UNLIKELY (ret < 0)) {
876 GST_WARNING_OBJECT (tiger,
877 "Tiger renderer failed to set buffer to video frame: %s",
878 gst_kate_util_get_error_message (ret));
879 goto pass;
880 }
881 ret = tiger_renderer_render (tiger->tr);
882 if (G_UNLIKELY (ret < 0)) {
883 GST_WARNING_OBJECT (tiger,
884 "Tiger renderer failed to render to video frame: %s",
885 gst_kate_util_get_error_message (ret));
886 } else {
887 GST_LOG_OBJECT (tiger, "Tiger renderer rendered on video frame at %f", t);
888 }
889
890 if (gst_video_format_is_yuv (tiger->video_format)) {
891 gst_kate_tiger_set_composition (tiger);
892 if (tiger->composition)
893 gst_video_overlay_composition_blend (tiger->composition, buf);
894 }
895
896 pass:
897 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
898
899 rflow = gst_pad_push (tiger->srcpad, buf);
900
901 gst_object_unref (tiger);
902
903 return rflow;
904 }
905
906 static GstStateChangeReturn
gst_kate_tiger_change_state(GstElement * element,GstStateChange transition)907 gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
908 {
909 GstKateTiger *tiger = GST_KATE_TIGER (element);
910 GstStateChangeReturn res;
911
912 switch (transition) {
913 case GST_STATE_CHANGE_PAUSED_TO_READY:
914 GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state");
915 GST_KATE_TIGER_MUTEX_LOCK (tiger);
916 gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
917 g_cond_broadcast (tiger->cond);
918 if (tiger->tr) {
919 tiger_renderer_destroy (tiger->tr);
920 tiger->tr = NULL;
921 }
922 gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
923 tiger->video_flushing = TRUE;
924 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
925 break;
926 default:
927 break;
928 }
929
930 res =
931 gst_kate_decoder_base_change_state (&tiger->decoder, element,
932 parent_class, transition);
933
934 switch (transition) {
935 case GST_STATE_CHANGE_READY_TO_PAUSED:
936 GST_DEBUG_OBJECT (tiger, "READY -> PAUSED, initializing kate state");
937 GST_KATE_TIGER_MUTEX_LOCK (tiger);
938 if (tiger->decoder.initialized) {
939 int ret = tiger_renderer_create (&tiger->tr);
940 if (ret < 0) {
941 GST_WARNING_OBJECT (tiger, "failed to create tiger renderer: %s",
942 gst_kate_util_get_error_message (ret));
943 } else {
944 ret =
945 tiger_renderer_set_default_font_description (tiger->tr,
946 tiger->default_font_desc);
947 if (ret < 0) {
948 GST_WARNING_OBJECT (tiger,
949 "failed to set tiger default font description: %s",
950 gst_kate_util_get_error_message (ret));
951 }
952 gst_kate_tiger_update_default_font_color (tiger);
953 gst_kate_tiger_update_default_background_color (tiger);
954 gst_kate_tiger_update_default_font_effect (tiger);
955 gst_kate_tiger_update_quality (tiger);
956 }
957 }
958 gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
959 tiger->video_flushing = FALSE;
960 tiger->seen_header = FALSE;
961 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
962 break;
963 default:
964 break;
965 }
966
967 return res;
968 }
969
970 static gboolean
gst_kate_tiger_seek(GstKateTiger * tiger,GstPad * pad,GstEvent * event)971 gst_kate_tiger_seek (GstKateTiger * tiger, GstPad * pad, GstEvent * event)
972 {
973 GstFormat format;
974 gdouble rate;
975 GstSeekFlags flags;
976 GstSeekType cur_type, stop_type;
977 gint64 cur, stop;
978
979 gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
980 &stop_type, &stop);
981
982 if (flags & GST_SEEK_FLAG_FLUSH)
983 gst_pad_push_event (tiger->srcpad, gst_event_new_flush_start ());
984
985 GST_KATE_TIGER_MUTEX_LOCK (tiger);
986 tiger->video_flushing = TRUE;
987 gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
988 g_cond_broadcast (tiger->cond);
989 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
990
991 if (format == GST_FORMAT_TIME) {
992 /* if seeking in time, we can update tiger to remove any appropriate events */
993 kate_float target;
994 switch (cur_type) {
995 case GST_SEEK_TYPE_SET:
996 target = cur / (float) GST_SECOND;
997 break;
998 case GST_SEEK_TYPE_CUR:
999 GST_WARNING_OBJECT (tiger,
1000 "Seeking from the current segment, cannot work out target so flushing everything");
1001 target = (kate_float) 0;
1002 break;
1003 case GST_SEEK_TYPE_END:
1004 GST_WARNING_OBJECT (tiger,
1005 "Seeking from the end, cannot work out target so flushing everything");
1006 target = (kate_float) 0;
1007 break;
1008 default:
1009 GST_WARNING_OBJECT (tiger, "Unexpected seek type");
1010 target = (kate_float) 0;
1011 break;
1012 }
1013 GST_INFO_OBJECT (tiger, "Seeking in time to %f", target);
1014 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1015 tiger_renderer_seek (tiger->tr, target);
1016 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1017 }
1018
1019 /* forward to both sinks */
1020 gst_event_ref (event);
1021 if (gst_pad_push_event (tiger->videosinkpad, event)) {
1022 int ret = gst_pad_push_event (tiger->katesinkpad, event);
1023 if (ret) {
1024 return TRUE;
1025 } else {
1026 return FALSE;
1027 }
1028 } else {
1029 gst_event_unref (event);
1030 return FALSE;
1031 }
1032 }
1033
1034 static gboolean
gst_kate_tiger_source_event(GstPad * pad,GstEvent * event)1035 gst_kate_tiger_source_event (GstPad * pad, GstEvent * event)
1036 {
1037 GstKateTiger *tiger =
1038 (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
1039 gboolean res = TRUE;
1040
1041 g_return_val_if_fail (tiger != NULL, FALSE);
1042
1043 GST_LOG_OBJECT (tiger, "Event on source pad: %s",
1044 GST_EVENT_TYPE_NAME (event));
1045
1046 switch (GST_EVENT_TYPE (event)) {
1047 case GST_EVENT_SEEK:
1048 GST_INFO_OBJECT (tiger, "Seek on source pad");
1049 res = gst_kate_tiger_seek (tiger, pad, event);
1050 break;
1051 default:
1052 res = gst_pad_event_default (pad, event);
1053 break;
1054 }
1055
1056 gst_object_unref (tiger);
1057
1058 return res;
1059 }
1060
1061 static gboolean
gst_kate_tiger_handle_kate_event(GstPad * pad,GstEvent * event)1062 gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event)
1063 {
1064 GstKateTiger *tiger =
1065 (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
1066 gboolean res = TRUE;
1067
1068 switch (GST_EVENT_TYPE (event)) {
1069 case GST_EVENT_NEWSEGMENT:
1070 GST_INFO_OBJECT (tiger, "New segment on Kate pad");
1071 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1072 g_cond_broadcast (tiger->cond);
1073 gst_kate_util_decoder_base_new_segment_event (&tiger->decoder, event);
1074 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1075 gst_event_unref (event);
1076 break;
1077 case GST_EVENT_FLUSH_START:
1078 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1079 gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
1080 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1081 g_cond_broadcast (tiger->cond);
1082 gst_event_unref (event);
1083 break;
1084 case GST_EVENT_FLUSH_STOP:
1085 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1086 gst_kate_util_decoder_base_set_flushing (&tiger->decoder, FALSE);
1087 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1088 gst_event_unref (event);
1089 break;
1090 case GST_EVENT_EOS:
1091 /* we ignore this, it just means we don't have anymore Kate packets, but
1092 the Tiger renderer will still draw (if appropriate) on incoming video */
1093 GST_INFO_OBJECT (tiger, "EOS on Kate pad");
1094 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1095 g_cond_broadcast (tiger->cond);
1096 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1097 gst_event_unref (event);
1098 break;
1099 default:
1100 res = gst_pad_event_default (pad, event);
1101 break;
1102 }
1103
1104 gst_object_unref (tiger);
1105
1106 return res;
1107 }
1108
1109 static gboolean
gst_kate_tiger_kate_event(GstPad * pad,GstEvent * event)1110 gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event)
1111 {
1112 GstKateTiger *tiger =
1113 (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
1114 gboolean res = TRUE;
1115
1116 g_return_val_if_fail (tiger != NULL, FALSE);
1117
1118 GST_LOG_OBJECT (tiger, "Event on Kate pad: %s", GST_EVENT_TYPE_NAME (event));
1119
1120 /* Delay events till we've set caps */
1121 if (gst_kate_util_decoder_base_queue_event (&tiger->decoder, event,
1122 &gst_kate_tiger_handle_kate_event, pad)) {
1123 gst_object_unref (tiger);
1124 return TRUE;
1125 }
1126
1127 res = gst_kate_tiger_handle_kate_event (pad, event);
1128
1129 gst_object_unref (tiger);
1130
1131 return res;
1132 }
1133
1134 static gboolean
gst_kate_tiger_handle_video_event(GstPad * pad,GstEvent * event)1135 gst_kate_tiger_handle_video_event (GstPad * pad, GstEvent * event)
1136 {
1137 GstKateTiger *tiger =
1138 (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
1139 gboolean res = TRUE;
1140
1141 switch (GST_EVENT_TYPE (event)) {
1142 case GST_EVENT_NEWSEGMENT:
1143 {
1144 gboolean update;
1145 gdouble rate, arate;
1146 GstFormat format;
1147 gint64 start, stop, time;
1148
1149 gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1150 &start, &stop, &time);
1151
1152 if (format == GST_FORMAT_TIME) {
1153 GST_DEBUG_OBJECT (tiger, "video pad segment:"
1154 " Update %d, rate %g arate %g format %d start %" GST_TIME_FORMAT
1155 " %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT,
1156 update, rate, arate, format, GST_TIME_ARGS (start),
1157 GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
1158
1159 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1160 gst_segment_set_newsegment_full (&tiger->video_segment, update, rate,
1161 arate, format, start, stop, time);
1162 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1163 }
1164
1165 res = gst_pad_event_default (pad, event);
1166 break;
1167 }
1168 case GST_EVENT_FLUSH_START:
1169 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1170 gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
1171 tiger->video_flushing = TRUE;
1172 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1173 g_cond_broadcast (tiger->cond);
1174 res = gst_pad_event_default (pad, event);
1175 break;
1176 case GST_EVENT_FLUSH_STOP:
1177 GST_KATE_TIGER_MUTEX_LOCK (tiger);
1178 gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
1179 tiger->video_flushing = FALSE;
1180 GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
1181 res = gst_pad_event_default (pad, event);
1182 break;
1183 default:
1184 res = gst_pad_event_default (pad, event);
1185 break;
1186 }
1187
1188 gst_object_unref (tiger);
1189
1190 return res;
1191 }
1192
1193 static gboolean
gst_kate_tiger_video_event(GstPad * pad,GstEvent * event)1194 gst_kate_tiger_video_event (GstPad * pad, GstEvent * event)
1195 {
1196 GstKateTiger *tiger =
1197 (GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
1198 gboolean res = TRUE;
1199
1200 g_return_val_if_fail (tiger != NULL, FALSE);
1201
1202 GST_INFO_OBJECT (tiger, "Event on video pad: %s",
1203 GST_EVENT_TYPE_NAME (event));
1204
1205 res = gst_kate_tiger_handle_video_event (pad, event);
1206
1207 gst_object_unref (tiger);
1208
1209 return res;
1210 }
1211
1212 gboolean
gst_kate_tiger_kate_sink_query(GstPad * pad,GstQuery * query)1213 gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query)
1214 {
1215 GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
1216 gboolean res = gst_kate_decoder_base_sink_query (&tiger->decoder,
1217 GST_ELEMENT_CAST (tiger), pad, query);
1218 GST_INFO_OBJECT (tiger, "Query on Kate pad");
1219 gst_object_unref (tiger);
1220 return res;
1221 }
1222