kate: Initialize debug categories
[platform/upstream/gstreamer.git] / ext / kate / gstkatetiger.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }