mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-21 07:46:38 +00:00
857e3dda46
When Totem switches streams, tiger will be reset, and start receiving buffers from the middle of the stream, without being sent headers. If this happens, try to get headers from the caps. https://bugzilla.gnome.org/show_bug.cgi?id=638004
1050 lines
34 KiB
C
1050 lines
34 KiB
C
/*
|
|
* GStreamer
|
|
* Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
|
|
* Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
|
|
* Copyright 2008 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
|
* which case the following provisions apply instead of the ones
|
|
* mentioned above:
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:element-tiger
|
|
* @see_also: katedec
|
|
*
|
|
* <refsect2>
|
|
* <para>
|
|
* This element decodes and renders Kate streams
|
|
* <ulink url="http://libkate.googlecode.com/">Kate</ulink> is a free codec
|
|
* for text based data, such as subtitles. Any number of kate streams can be
|
|
* embedded in an Ogg stream.
|
|
* </para>
|
|
* <para>
|
|
* libkate (see above url) and <ulink url="http://libtiger.googlecode.com/">libtiger</ulink>
|
|
* are needed to build this element.
|
|
* </para>
|
|
* <title>Example pipeline</title>
|
|
* <para>
|
|
* This pipeline renders a Kate stream on top of a Theora video multiplexed
|
|
* in the same stream:
|
|
* <programlisting>
|
|
* gst-launch \
|
|
* filesrc location=video.ogg ! oggdemux name=demux \
|
|
* demux. ! queue ! theoradec ! ffmpegcolorspace ! tiger name=tiger \
|
|
* demux. ! queue ! kateparse ! tiger. \
|
|
* tiger. ! ffmpegcolorspace ! autovideosink
|
|
* </programlisting>
|
|
* </para>
|
|
* </refsect2>
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
|
|
#include <gst/gst.h>
|
|
#include <gst/video/video.h>
|
|
|
|
#include "gstkate.h"
|
|
#include "gstkatetiger.h"
|
|
|
|
GST_DEBUG_CATEGORY_EXTERN (gst_katetiger_debug);
|
|
#define GST_CAT_DEFAULT gst_katetiger_debug
|
|
|
|
#define GST_KATE_TIGER_MUTEX_LOCK(element) \
|
|
do { \
|
|
/*GST_LOG_OBJECT ((element), "locking from %s:%d\n",__FILE__,__LINE__);*/ \
|
|
g_mutex_lock ((element)->mutex); \
|
|
/*GST_LOG_OBJECT ((element), "ready from %s:%d\n",__FILE__,__LINE__);*/ \
|
|
} while(0)
|
|
|
|
#define GST_KATE_TIGER_MUTEX_UNLOCK(element) \
|
|
do { \
|
|
/*GST_LOG_OBJECT ((element), "unlocking from %s:%d\n",__FILE__,__LINE__);*/ \
|
|
g_mutex_unlock ((element)->mutex); \
|
|
} while(0)
|
|
|
|
/* Filter signals and args */
|
|
enum
|
|
{
|
|
/* FILL ME */
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
enum
|
|
{
|
|
ARG_DEFAULT_FONT_DESC = DECODER_BASE_ARG_COUNT,
|
|
ARG_QUALITY,
|
|
ARG_DEFAULT_FONT_EFFECT,
|
|
ARG_DEFAULT_FONT_EFFECT_STRENGTH,
|
|
ARG_DEFAULT_FONT_RED,
|
|
ARG_DEFAULT_FONT_GREEN,
|
|
ARG_DEFAULT_FONT_BLUE,
|
|
ARG_DEFAULT_FONT_ALPHA,
|
|
ARG_DEFAULT_BACKGROUND_RED,
|
|
ARG_DEFAULT_BACKGROUND_GREEN,
|
|
ARG_DEFAULT_BACKGROUND_BLUE,
|
|
ARG_DEFAULT_BACKGROUND_ALPHA
|
|
};
|
|
|
|
static GstStaticPadTemplate kate_sink_factory =
|
|
GST_STATIC_PAD_TEMPLATE ("subtitle_sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate")
|
|
);
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
#define TIGER_VIDEO_CAPS \
|
|
GST_VIDEO_CAPS_xRGB ", endianness = (int)1234; " \
|
|
GST_VIDEO_CAPS_BGRx ", endianness = (int)4321"
|
|
#else
|
|
#define TIGER_VIDEO_CAPS \
|
|
GST_VIDEO_CAPS_BGRx ", endianness = (int)4321; " \
|
|
GST_VIDEO_CAPS_xRGB ", endianness = (int)1234"
|
|
#endif
|
|
|
|
static GstStaticPadTemplate video_sink_factory =
|
|
GST_STATIC_PAD_TEMPLATE ("video_sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS (TIGER_VIDEO_CAPS));
|
|
|
|
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS (TIGER_VIDEO_CAPS));
|
|
|
|
GST_BOILERPLATE (GstKateTiger, gst_kate_tiger, GstElement, GST_TYPE_ELEMENT);
|
|
|
|
static GType
|
|
gst_kate_tiger_font_effect_get_type (void)
|
|
{
|
|
static GType font_effect_type = 0;
|
|
|
|
if (!font_effect_type) {
|
|
static const GEnumValue font_effects[] = {
|
|
{tiger_font_plain, "none", "none"},
|
|
{tiger_font_shadow, "shadow", "shadow"},
|
|
{tiger_font_outline, "outline", "outline"},
|
|
{0, NULL, NULL}
|
|
};
|
|
font_effect_type = g_enum_register_static ("GstFontEffect", font_effects);
|
|
}
|
|
|
|
return font_effect_type;
|
|
}
|
|
|
|
static void gst_kate_tiger_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec);
|
|
static void gst_kate_tiger_get_property (GObject * object, guint prop_id,
|
|
GValue * value, GParamSpec * pspec);
|
|
static void gst_kate_tiger_dispose (GObject * object);
|
|
|
|
static GstFlowReturn gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf);
|
|
static GstFlowReturn gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf);
|
|
static GstStateChangeReturn gst_kate_tiger_change_state (GstElement * element,
|
|
GstStateChange transition);
|
|
static gboolean gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query);
|
|
static gboolean gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event);
|
|
static gboolean gst_kate_tiger_video_event (GstPad * pad, GstEvent * event);
|
|
static gboolean gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps);
|
|
static gboolean gst_kate_tiger_source_event (GstPad * pad, GstEvent * event);
|
|
|
|
static void
|
|
gst_kate_tiger_base_init (gpointer gclass)
|
|
{
|
|
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&src_factory));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&kate_sink_factory));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&video_sink_factory));
|
|
gst_element_class_set_details_simple (element_class, "Kate stream renderer",
|
|
"Mixer/Video/Overlay/Subtitle",
|
|
"Decodes and renders Kate streams on top of a video",
|
|
"Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
|
|
}
|
|
|
|
/* initialize the plugin's class */
|
|
static void
|
|
gst_kate_tiger_class_init (GstKateTigerClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GstElementClass *gstelement_class;
|
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
gstelement_class = (GstElementClass *) klass;
|
|
|
|
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_tiger_get_property);
|
|
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_tiger_set_property);
|
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_kate_tiger_dispose);
|
|
|
|
gst_kate_util_install_decoder_base_properties (gobject_class);
|
|
|
|
g_object_class_install_property (gobject_class, ARG_QUALITY,
|
|
g_param_spec_double ("quality", "Rendering quality",
|
|
"Rendering quality (0 is faster, 1 is best and slower)",
|
|
0.0, 1.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_DESC,
|
|
g_param_spec_string ("default-font-desc", "Default font description",
|
|
"Default font description (Pango style) to render text with",
|
|
"", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_EFFECT,
|
|
g_param_spec_enum ("default-font-effect", "Default font effect",
|
|
"Whether to apply an effect to text by default, for increased readability",
|
|
gst_kate_tiger_font_effect_get_type (),
|
|
tiger_font_plain,
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
ARG_DEFAULT_FONT_EFFECT_STRENGTH,
|
|
g_param_spec_double ("default-font-effect-strength",
|
|
"Default font effect strength",
|
|
"How pronounced should the font effect be (effect dependent)", 0.0,
|
|
1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_RED,
|
|
g_param_spec_int ("default-font-red",
|
|
"Default font color (red component)",
|
|
"Default font color (red component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_GREEN,
|
|
g_param_spec_int ("default-font-green",
|
|
"Default font color (green component)",
|
|
"Default font color (green component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_BLUE,
|
|
g_param_spec_int ("default-font-blue",
|
|
"Default font color (blue component)",
|
|
"Default font color (blue component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_FONT_ALPHA,
|
|
g_param_spec_int ("default-font-alpha",
|
|
"Default font color (alpha component)",
|
|
"Default font color (alpha component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_RED,
|
|
g_param_spec_int ("default-background-red",
|
|
"Default background color (red component)",
|
|
"Default background color (red component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_GREEN,
|
|
g_param_spec_int ("default-background-green",
|
|
"Default background color (green component)",
|
|
"Default background color (green component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_BLUE,
|
|
g_param_spec_int ("default-background-blue",
|
|
"Default background color (blue component)",
|
|
"Default background color (blue component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (gobject_class, ARG_DEFAULT_BACKGROUND_ALPHA,
|
|
g_param_spec_int ("default-background-alpha",
|
|
"Default background color (alpha component)",
|
|
"Default background color (alpha component, between 0 and 255) to render text with",
|
|
0, 255, 255, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
gstelement_class->change_state =
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_change_state);
|
|
}
|
|
|
|
/* initialize the new element
|
|
* instantiate pads and add them to element
|
|
* set functions
|
|
* initialize structure
|
|
*/
|
|
static void
|
|
gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass)
|
|
{
|
|
GST_DEBUG_OBJECT (tiger, "gst_kate_tiger_init");
|
|
|
|
tiger->mutex = g_mutex_new ();
|
|
|
|
tiger->katesinkpad =
|
|
gst_pad_new_from_static_template (&kate_sink_factory, "subtitle_sink");
|
|
gst_pad_set_chain_function (tiger->katesinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_chain));
|
|
gst_pad_set_query_function (tiger->katesinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_sink_query));
|
|
gst_pad_set_event_function (tiger->katesinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_kate_event));
|
|
gst_element_add_pad (GST_ELEMENT (tiger), tiger->katesinkpad);
|
|
|
|
tiger->videosinkpad =
|
|
gst_pad_new_from_static_template (&video_sink_factory, "video_sink");
|
|
gst_pad_set_chain_function (tiger->videosinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_video_chain));
|
|
gst_pad_use_fixed_caps (tiger->videosinkpad);
|
|
gst_pad_set_setcaps_function (tiger->videosinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_video_set_caps));
|
|
gst_pad_set_event_function (tiger->videosinkpad,
|
|
GST_DEBUG_FUNCPTR (gst_kate_tiger_video_event));
|
|
gst_element_add_pad (GST_ELEMENT (tiger), tiger->videosinkpad);
|
|
|
|
tiger->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
|
|
gst_pad_set_event_function (tiger->srcpad, gst_kate_tiger_source_event);
|
|
gst_pad_use_fixed_caps (tiger->srcpad);
|
|
gst_element_add_pad (GST_ELEMENT (tiger), tiger->srcpad);
|
|
|
|
gst_kate_util_decode_base_init (&tiger->decoder, FALSE);
|
|
|
|
tiger->tr = NULL;
|
|
|
|
tiger->default_font_desc = NULL;
|
|
tiger->quality = -1.0;
|
|
tiger->default_font_effect = tiger_font_plain;
|
|
tiger->default_font_effect_strength = 0.5;
|
|
tiger->default_font_r = 255;
|
|
tiger->default_font_g = 255;
|
|
tiger->default_font_b = 255;
|
|
tiger->default_font_a = 255;
|
|
tiger->default_background_r = 0;
|
|
tiger->default_background_g = 0;
|
|
tiger->default_background_b = 0;
|
|
tiger->default_background_a = 0;
|
|
|
|
tiger->video_width = 0;
|
|
tiger->video_height = 0;
|
|
|
|
tiger->seen_header = FALSE;
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_dispose (GObject * object)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (object);
|
|
|
|
GST_LOG_OBJECT (tiger, "disposing");
|
|
|
|
if (tiger->default_font_desc) {
|
|
g_free (tiger->default_font_desc);
|
|
tiger->default_font_desc = NULL;
|
|
}
|
|
|
|
g_mutex_free (tiger->mutex);
|
|
tiger->mutex = NULL;
|
|
|
|
GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_update_quality (GstKateTiger * tiger)
|
|
{
|
|
if (tiger->tr && tiger->quality >= 0.0) {
|
|
tiger_renderer_set_quality (tiger->tr, tiger->quality);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_update_default_font_effect (GstKateTiger * tiger)
|
|
{
|
|
if (tiger->tr) {
|
|
tiger_renderer_set_default_font_effect (tiger->tr,
|
|
tiger->default_font_effect, tiger->default_font_effect_strength);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_update_default_font_color (GstKateTiger * tiger)
|
|
{
|
|
if (tiger->tr) {
|
|
tiger_renderer_set_default_font_color (tiger->tr,
|
|
tiger->default_font_r / 255.0,
|
|
tiger->default_font_g / 255.0,
|
|
tiger->default_font_b / 255.0, tiger->default_font_a / 255.0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_update_default_background_color (GstKateTiger * tiger)
|
|
{
|
|
if (tiger->tr) {
|
|
tiger_renderer_set_default_background_fill_color (tiger->tr,
|
|
tiger->default_background_r / 255.0,
|
|
tiger->default_background_g / 255.0,
|
|
tiger->default_background_b / 255.0,
|
|
tiger->default_background_a / 255.0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (object);
|
|
const char *str;
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
|
|
switch (prop_id) {
|
|
case ARG_DEFAULT_FONT_DESC:
|
|
if (tiger->default_font_desc) {
|
|
g_free (tiger->default_font_desc);
|
|
tiger->default_font_desc = NULL;
|
|
}
|
|
str = g_value_get_string (value);
|
|
if (str) {
|
|
tiger->default_font_desc = g_strdup (str);
|
|
if (tiger->tr)
|
|
tiger_renderer_set_default_font_description (tiger->tr,
|
|
tiger->default_font_desc);
|
|
}
|
|
break;
|
|
case ARG_QUALITY:
|
|
tiger->quality = g_value_get_double (value);
|
|
gst_kate_tiger_update_quality (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_EFFECT:
|
|
tiger->default_font_effect = g_value_get_enum (value);
|
|
gst_kate_tiger_update_default_font_effect (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_EFFECT_STRENGTH:
|
|
tiger->default_font_effect_strength = g_value_get_double (value);
|
|
gst_kate_tiger_update_default_font_effect (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_RED:
|
|
tiger->default_font_r = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_font_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_GREEN:
|
|
tiger->default_font_g = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_font_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_BLUE:
|
|
tiger->default_font_b = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_font_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_FONT_ALPHA:
|
|
tiger->default_font_a = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_font_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_RED:
|
|
tiger->default_background_r = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_background_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_GREEN:
|
|
tiger->default_background_g = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_background_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_BLUE:
|
|
tiger->default_background_b = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_background_color (tiger);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_ALPHA:
|
|
tiger->default_background_a = g_value_get_int (value);
|
|
gst_kate_tiger_update_default_background_color (tiger);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
}
|
|
|
|
static void
|
|
gst_kate_tiger_get_property (GObject * object, guint prop_id,
|
|
GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (object);
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
|
|
switch (prop_id) {
|
|
case ARG_DEFAULT_FONT_DESC:
|
|
g_value_set_string (value,
|
|
tiger->default_font_desc ? tiger->default_font_desc : "");
|
|
break;
|
|
case ARG_QUALITY:
|
|
g_value_set_double (value, tiger->quality);
|
|
break;
|
|
case ARG_DEFAULT_FONT_EFFECT:
|
|
g_value_set_enum (value, tiger->default_font_effect);
|
|
break;
|
|
case ARG_DEFAULT_FONT_EFFECT_STRENGTH:
|
|
g_value_set_double (value, tiger->default_font_effect_strength);
|
|
break;
|
|
case ARG_DEFAULT_FONT_RED:
|
|
g_value_set_int (value, tiger->default_font_r);
|
|
break;
|
|
case ARG_DEFAULT_FONT_GREEN:
|
|
g_value_set_int (value, tiger->default_font_g);
|
|
break;
|
|
case ARG_DEFAULT_FONT_BLUE:
|
|
g_value_set_int (value, tiger->default_font_b);
|
|
break;
|
|
case ARG_DEFAULT_FONT_ALPHA:
|
|
g_value_set_int (value, tiger->default_font_a);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_RED:
|
|
g_value_set_int (value, tiger->default_background_r);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_GREEN:
|
|
g_value_set_int (value, tiger->default_background_g);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_BLUE:
|
|
g_value_set_int (value, tiger->default_background_b);
|
|
break;
|
|
case ARG_DEFAULT_BACKGROUND_ALPHA:
|
|
g_value_set_int (value, tiger->default_background_a);
|
|
break;
|
|
default:
|
|
if (!gst_kate_util_decoder_base_get_property (&tiger->decoder, object,
|
|
prop_id, value, pspec)) {
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
break;
|
|
}
|
|
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
}
|
|
|
|
/* GstElement vmethod implementations */
|
|
|
|
/* chain function
|
|
* this function does the actual processing
|
|
*/
|
|
|
|
static GstFlowReturn
|
|
gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
|
|
const kate_event *ev = NULL;
|
|
GstFlowReturn rflow = GST_FLOW_OK;
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
|
|
GST_LOG_OBJECT (tiger, "Got kate buffer, caps %s",
|
|
gst_caps_to_string (GST_BUFFER_CAPS (buf)));
|
|
|
|
/* Unfortunately, it can happen that the start of the stream is not sent,
|
|
for instance if there's a stream selector upstream, which is switched
|
|
from another Kate stream. If this happens, then we can fallback on the
|
|
headers stored in the caps (if any). */
|
|
if (!tiger->seen_header) {
|
|
if (GST_BUFFER_SIZE (buf) == 0 || (GST_BUFFER_DATA (buf)[0] & 0x80) == 0) {
|
|
/* Not a header, try to fall back on caps */
|
|
GstStructure *s;
|
|
const GValue *streamheader;
|
|
|
|
GST_INFO_OBJECT (tiger, "Headers not seen, start of stream is cut off");
|
|
s = gst_caps_get_structure (GST_BUFFER_CAPS (buf), 0);
|
|
streamheader = gst_structure_get_value (s, "streamheader");
|
|
if (streamheader && G_VALUE_TYPE (streamheader) == GST_TYPE_ARRAY) {
|
|
GstPad *tagpad = gst_pad_get_peer (pad);
|
|
GArray *array;
|
|
gint i;
|
|
|
|
GST_INFO_OBJECT (tiger, "Falling back on caps to initialize decoder");
|
|
array = g_value_peek_pointer (streamheader);
|
|
for (i = 0; i < array->len; i++) {
|
|
GValue *value = &g_array_index (array, GValue, i);
|
|
if (G_VALUE_TYPE (value) == GST_TYPE_BUFFER) {
|
|
GstBuffer *hbuf = g_value_peek_pointer (value);
|
|
gst_buffer_ref (hbuf);
|
|
rflow =
|
|
gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder,
|
|
GST_ELEMENT_CAST (tiger), pad, hbuf, tiger->srcpad, tagpad,
|
|
NULL, NULL);
|
|
} else {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Streamheader index %d does not hold a buffer", i);
|
|
}
|
|
}
|
|
gst_object_unref (tagpad);
|
|
tiger->seen_header = TRUE;
|
|
} else {
|
|
GST_WARNING_OBJECT (tiger, "No headers seen, and no headers on caps");
|
|
}
|
|
} else {
|
|
tiger->seen_header = TRUE;
|
|
}
|
|
}
|
|
|
|
if (gst_kate_util_decoder_base_update_segment (&tiger->decoder,
|
|
GST_ELEMENT_CAST (tiger), buf)) {
|
|
GstPad *tagpad = gst_pad_get_peer (pad);
|
|
rflow =
|
|
gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder,
|
|
GST_ELEMENT_CAST (tiger), pad, buf, tiger->srcpad, tagpad, NULL, &ev);
|
|
if (G_LIKELY (rflow == GST_FLOW_OK)) {
|
|
if (ev) {
|
|
int ret = tiger_renderer_add_event (tiger->tr, ev->ki, ev);
|
|
GST_INFO_OBJECT (tiger, "adding event for %p from %f to %f: %p, \"%s\"",
|
|
ev->ki, ev->start_time, ev->end_time, ev->bitmap, ev->text);
|
|
if (G_UNLIKELY (ret < 0)) {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"failed to add Kate event to Tiger renderer: %d", ret);
|
|
}
|
|
}
|
|
}
|
|
gst_object_unref (tagpad);
|
|
}
|
|
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
|
|
gst_object_unref (tiger);
|
|
gst_buffer_unref (buf);
|
|
|
|
return rflow;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
|
|
GstVideoFormat format;
|
|
gint w, h;
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
|
|
/* Cairo expects ARGB in native endianness, and that's what we get
|
|
as we've forced it in the caps. We might allow swapped red/blue
|
|
at some point, and get tiger to swap, to make some cases faster */
|
|
tiger->swap_rgb = FALSE;
|
|
|
|
if (gst_video_format_parse_caps (caps, &format, &w, &h)) {
|
|
tiger->video_width = w;
|
|
tiger->video_height = h;
|
|
}
|
|
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
|
|
gst_pad_set_caps (tiger->srcpad, caps);
|
|
|
|
gst_object_unref (tiger);
|
|
return TRUE;
|
|
}
|
|
|
|
static gdouble
|
|
gst_kate_tiger_get_time (GstKateTiger * tiger)
|
|
{
|
|
return gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME,
|
|
tiger->video_segment.last_stop) / (gdouble) GST_SECOND;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
|
|
GstFlowReturn rflow = GST_FLOW_OK;
|
|
unsigned char *ptr;
|
|
int ret;
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
|
|
GST_LOG_OBJECT (tiger, "got video frame, %u bytes", GST_BUFFER_SIZE (buf));
|
|
|
|
if (G_UNLIKELY (tiger->video_flushing)) {
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
gst_object_unref (tiger);
|
|
gst_buffer_unref (buf);
|
|
return GST_FLOW_WRONG_STATE;
|
|
}
|
|
|
|
if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
|
|
gst_segment_set_last_stop (&tiger->video_segment, GST_FORMAT_TIME,
|
|
GST_BUFFER_TIMESTAMP (buf));
|
|
}
|
|
|
|
/* draw on it */
|
|
buf = gst_buffer_make_writable (buf);
|
|
if (G_UNLIKELY (!buf)) {
|
|
GST_WARNING_OBJECT (tiger, "Failed to make video buffer writable");
|
|
} else {
|
|
ptr = GST_BUFFER_DATA (buf);
|
|
if (!ptr) {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Failed to get a pointer to video buffer data");
|
|
} else {
|
|
ret =
|
|
tiger_renderer_set_buffer (tiger->tr, ptr, tiger->video_width,
|
|
tiger->video_height, tiger->video_width * 4, tiger->swap_rgb);
|
|
if (G_UNLIKELY (ret < 0)) {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Tiger renderer failed to set buffer to video frame: %d", ret);
|
|
} else {
|
|
kate_float t = gst_kate_tiger_get_time (tiger);
|
|
GST_LOG_OBJECT (tiger, "Video segment calc: last stop %ld, time %.3f",
|
|
(long) tiger->video_segment.last_stop, t);
|
|
|
|
ret = tiger_renderer_update (tiger->tr, t, 1);
|
|
if (G_UNLIKELY (ret < 0)) {
|
|
GST_WARNING_OBJECT (tiger, "Tiger renderer failed to update: %d",
|
|
ret);
|
|
} else {
|
|
ret = tiger_renderer_render (tiger->tr);
|
|
if (G_UNLIKELY (ret < 0)) {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Tiger renderer failed to render to video frame: %d", ret);
|
|
} else {
|
|
GST_LOG_OBJECT (tiger,
|
|
"Tiger renderer rendered on video frame at %f", t);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
|
|
rflow = gst_pad_push (tiger->srcpad, buf);
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return rflow;
|
|
}
|
|
|
|
static GstStateChangeReturn
|
|
gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (element);
|
|
GstStateChangeReturn res;
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state");
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
if (tiger->tr) {
|
|
tiger_renderer_destroy (tiger->tr);
|
|
tiger->tr = NULL;
|
|
}
|
|
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
|
|
tiger->video_flushing = TRUE;
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
res =
|
|
gst_kate_decoder_base_change_state (&tiger->decoder, element,
|
|
parent_class, transition);
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
GST_DEBUG_OBJECT (tiger, "READY -> PAUSED, initializing kate state");
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
if (tiger->decoder.initialized) {
|
|
int ret = tiger_renderer_create (&tiger->tr);
|
|
if (ret < 0) {
|
|
GST_WARNING_OBJECT (tiger, "failed to create tiger renderer: %d",
|
|
ret);
|
|
} else {
|
|
ret =
|
|
tiger_renderer_set_default_font_description (tiger->tr,
|
|
tiger->default_font_desc);
|
|
if (ret < 0) {
|
|
GST_WARNING_OBJECT (tiger,
|
|
"failed to set tiger default font description: %d", ret);
|
|
}
|
|
gst_kate_tiger_update_default_font_color (tiger);
|
|
gst_kate_tiger_update_default_background_color (tiger);
|
|
gst_kate_tiger_update_default_font_effect (tiger);
|
|
gst_kate_tiger_update_quality (tiger);
|
|
}
|
|
}
|
|
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
|
|
tiger->video_flushing = FALSE;
|
|
tiger->seen_header = FALSE;
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_seek (GstKateTiger * tiger, GstPad * pad, GstEvent * event)
|
|
{
|
|
GstFormat format;
|
|
gdouble rate;
|
|
GstSeekFlags flags;
|
|
GstSeekType cur_type, stop_type;
|
|
gint64 cur, stop;
|
|
|
|
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
|
|
&stop_type, &stop);
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
tiger->video_flushing = TRUE;
|
|
gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
|
|
if (format == GST_FORMAT_TIME) {
|
|
/* if seeking in time, we can update tiger to remove any appropriate events */
|
|
kate_float target;
|
|
switch (cur_type) {
|
|
case GST_SEEK_TYPE_SET:
|
|
target = cur / (float) GST_SECOND;
|
|
break;
|
|
case GST_SEEK_TYPE_CUR:
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Seeking from the current segment, cannot work out target so flushing everything");
|
|
target = (kate_float) 0;
|
|
break;
|
|
case GST_SEEK_TYPE_END:
|
|
GST_WARNING_OBJECT (tiger,
|
|
"Seeking from the end, cannot work out target so flushing everything");
|
|
target = (kate_float) 0;
|
|
break;
|
|
default:
|
|
GST_WARNING_OBJECT (tiger, "Unexpected seek type");
|
|
target = (kate_float) 0;
|
|
break;
|
|
}
|
|
GST_INFO_OBJECT (tiger, "Seeking in time to %f", target);
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
tiger_renderer_seek (tiger->tr, target);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
}
|
|
|
|
/* forward to both sinks */
|
|
gst_event_ref (event);
|
|
if (gst_pad_push_event (tiger->videosinkpad, event)) {
|
|
int ret = gst_pad_push_event (tiger->katesinkpad, event);
|
|
if (ret) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
gst_event_unref (event);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_source_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstKateTiger *tiger =
|
|
(GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
|
|
gboolean res = TRUE;
|
|
|
|
g_return_val_if_fail (tiger != NULL, FALSE);
|
|
|
|
GST_LOG_OBJECT (tiger, "Event on source pad: %s",
|
|
GST_EVENT_TYPE_NAME (event));
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_SEEK:
|
|
GST_INFO_OBJECT (tiger, "Seek on source pad");
|
|
res = gst_kate_tiger_seek (tiger, pad, event);
|
|
break;
|
|
default:
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
}
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstKateTiger *tiger =
|
|
(GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
|
|
gboolean res = TRUE;
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_NEWSEGMENT:
|
|
GST_INFO_OBJECT (tiger, "New segment on Kate pad");
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_kate_util_decoder_base_new_segment_event (&tiger->decoder, event);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
gst_event_unref (event);
|
|
break;
|
|
case GST_EVENT_FLUSH_START:
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
gst_event_unref (event);
|
|
break;
|
|
case GST_EVENT_FLUSH_STOP:
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_kate_util_decoder_base_set_flushing (&tiger->decoder, FALSE);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
gst_event_unref (event);
|
|
break;
|
|
case GST_EVENT_EOS:
|
|
/* we ignore this, it just means we don't have anymore Kate packets, but
|
|
the Tiger renderer will still draw (if appropriate) on incoming video */
|
|
GST_INFO_OBJECT (tiger, "EOS on Kate pad");
|
|
gst_event_unref (event);
|
|
break;
|
|
default:
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
}
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstKateTiger *tiger =
|
|
(GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
|
|
gboolean res = TRUE;
|
|
|
|
g_return_val_if_fail (tiger != NULL, FALSE);
|
|
|
|
GST_LOG_OBJECT (tiger, "Event on Kate pad: %s", GST_EVENT_TYPE_NAME (event));
|
|
|
|
/* Delay events till we've set caps */
|
|
if (gst_kate_util_decoder_base_queue_event (&tiger->decoder, event,
|
|
&gst_kate_tiger_handle_kate_event, pad)) {
|
|
gst_object_unref (tiger);
|
|
return TRUE;
|
|
}
|
|
|
|
res = gst_kate_tiger_handle_kate_event (pad, event);
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_handle_video_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstKateTiger *tiger =
|
|
(GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
|
|
gboolean res = TRUE;
|
|
|
|
switch (GST_EVENT_TYPE (event)) {
|
|
case GST_EVENT_NEWSEGMENT:
|
|
{
|
|
gboolean update;
|
|
gdouble rate, arate;
|
|
GstFormat format;
|
|
gint64 start, stop, time;
|
|
|
|
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
|
|
&start, &stop, &time);
|
|
|
|
if (format == GST_FORMAT_TIME) {
|
|
GST_DEBUG_OBJECT (tiger, "video pad segment:"
|
|
" Update %d, rate %g arate %g format %d start %" GST_TIME_FORMAT
|
|
" %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT,
|
|
update, rate, arate, format, GST_TIME_ARGS (start),
|
|
GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
|
|
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_segment_set_newsegment_full (&tiger->video_segment, update, rate,
|
|
arate, format, start, stop, time);
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
}
|
|
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
}
|
|
case GST_EVENT_FLUSH_START:
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
|
|
tiger->video_flushing = TRUE;
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
case GST_EVENT_FLUSH_STOP:
|
|
GST_KATE_TIGER_MUTEX_LOCK (tiger);
|
|
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
|
|
tiger->video_flushing = FALSE;
|
|
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
default:
|
|
res = gst_pad_event_default (pad, event);
|
|
break;
|
|
}
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
gst_kate_tiger_video_event (GstPad * pad, GstEvent * event)
|
|
{
|
|
GstKateTiger *tiger =
|
|
(GstKateTiger *) (gst_object_get_parent (GST_OBJECT (pad)));
|
|
gboolean res = TRUE;
|
|
|
|
g_return_val_if_fail (tiger != NULL, FALSE);
|
|
|
|
GST_INFO_OBJECT (tiger, "Event on video pad: %s",
|
|
GST_EVENT_TYPE_NAME (event));
|
|
|
|
res = gst_kate_tiger_handle_video_event (pad, event);
|
|
|
|
gst_object_unref (tiger);
|
|
|
|
return res;
|
|
}
|
|
|
|
gboolean
|
|
gst_kate_tiger_kate_sink_query (GstPad * pad, GstQuery * query)
|
|
{
|
|
GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
|
|
gboolean res = gst_kate_decoder_base_sink_query (&tiger->decoder,
|
|
GST_ELEMENT_CAST (tiger), pad, query);
|
|
GST_INFO_OBJECT (tiger, "Query on Kate pad");
|
|
gst_object_unref (tiger);
|
|
return res;
|
|
}
|