• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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