kate: add segment tracking, and various other improvements

https://bugzilla.gnome.org/show_bug.cgi?id=600929
This commit is contained in:
Vincent Penquerc'h 2010-01-25 18:58:38 +00:00 committed by Sebastian Dröge
parent 4422cca1d3
commit 8574e8f991
10 changed files with 602 additions and 94 deletions

View file

@ -10,7 +10,7 @@ endif
# flags used to compile this plugin
libgstkate_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(TIGER_CFLAGS) $(KATE_CFLAGS)
libgstkate_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) $(GST_LIBS) $(TIGER_LIBS) $(KATE_LIBS)
libgstkate_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) -lgsttag-$(GST_MAJORMINOR) $(GST_LIBS) $(TIGER_LIBS) $(KATE_LIBS)
libgstkate_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstkate_la_LIBTOOLFLAGS = --tag=disable-static

View file

@ -64,6 +64,7 @@ GST_DEBUG_CATEGORY (gst_katedec_debug);
GST_DEBUG_CATEGORY (gst_kateenc_debug);
GST_DEBUG_CATEGORY (gst_kateparse_debug);
GST_DEBUG_CATEGORY (gst_katetag_debug);
GST_DEBUG_CATEGORY (gst_kateutil_debug);
#ifdef HAVE_TIGER
GST_DEBUG_CATEGORY (gst_katetiger_debug);
#endif
@ -75,6 +76,8 @@ plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_kateenc_debug, "kateenc", 0, "Kate encoder");
GST_DEBUG_CATEGORY_INIT (gst_kateparse_debug, "kateparse", 0, "Kate parser");
GST_DEBUG_CATEGORY_INIT (gst_katetag_debug, "katetag", 0, "Kate tagger");
GST_DEBUG_CATEGORY_INIT (gst_kateutil_debug, "kateutil", 0,
"Kate utility functions");
#ifdef HAVE_TIGER
GST_DEBUG_CATEGORY_INIT (gst_katetiger_debug, "tiger", 0,
"Kate Tiger renderer");

View file

@ -128,6 +128,9 @@ static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstBuffer * buf);
static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element,
GstStateChange transition);
static gboolean gst_kate_dec_sink_query (GstPad * pad, GstQuery * query);
static gboolean gst_kate_dec_sink_event (GstPad * pad, GstEvent * event);
static gboolean gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event);
static GstCaps *gst_kate_dec_src_get_caps (GstPad * pad);
static void
gst_kate_dec_base_init (gpointer gclass)
@ -184,16 +187,21 @@ gst_kate_dec_init (GstKateDec * dec, GstKateDecClass * gclass)
GST_DEBUG_FUNCPTR (gst_kate_dec_chain));
gst_pad_set_query_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_kate_dec_sink_query));
gst_pad_set_event_function (dec->sinkpad,
GST_DEBUG_FUNCPTR (gst_kate_dec_sink_event));
gst_pad_use_fixed_caps (dec->sinkpad);
gst_pad_set_caps (dec->sinkpad,
gst_static_pad_template_get_caps (&sink_factory));
gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad);
dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (dec->srcpad,
GST_DEBUG_FUNCPTR (gst_kate_dec_src_get_caps));
gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad);
gst_kate_util_decode_base_init (&dec->decoder);
gst_kate_util_decode_base_init (&dec->decoder, TRUE);
dec->src_caps = NULL;
dec->remove_markup = FALSE;
}
@ -240,9 +248,16 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf)
const kate_event *ev = NULL;
GstFlowReturn rflow = GST_FLOW_OK;
if (!gst_kate_util_decoder_base_update_segment (&kd->decoder,
GST_ELEMENT_CAST (kd), buf)) {
GST_WARNING_OBJECT (kd, "Out of segment!");
goto not_in_seg;
}
rflow =
gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder,
GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, &ev);
GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, kd->srcpad, &kd->src_caps,
&ev);
if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
gst_object_unref (kd);
gst_buffer_unref (buf);
@ -336,6 +351,7 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf)
}
}
not_in_seg:
gst_object_unref (kd);
gst_buffer_unref (buf);
return rflow;
@ -345,6 +361,7 @@ static GstStateChangeReturn
gst_kate_dec_change_state (GstElement * element, GstStateChange transition)
{
GstKateDec *kd = GST_KATE_DEC (element);
return gst_kate_decoder_base_change_state (&kd->decoder, element,
parent_class, transition);
}
@ -359,3 +376,87 @@ gst_kate_dec_sink_query (GstPad * pad, GstQuery * query)
gst_object_unref (kd);
return res;
}
static gboolean
gst_kate_dec_sink_event (GstPad * pad, GstEvent * event)
{
GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
gboolean res = TRUE;
g_return_val_if_fail (kd != NULL, FALSE);
GST_LOG_OBJECT (kd, "Event on sink pad: %s", GST_EVENT_TYPE_NAME (event));
// Delay events till we've set caps
if (gst_kate_util_decoder_base_queue_event (&kd->decoder, event,
&gst_kate_dec_sink_handle_event, pad)) {
gst_object_unref (kd);
return TRUE;
}
res = gst_kate_dec_sink_handle_event (pad, event);
gst_object_unref (kd);
return res;
}
static gboolean
gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event)
{
GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
gboolean res = TRUE;
g_return_val_if_fail (kd != NULL, FALSE);
GST_LOG_OBJECT (kd, "Handling event on sink pad: %s",
GST_EVENT_TYPE_NAME (event));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_NEWSEGMENT:
gst_kate_util_decoder_base_new_segment_event (&kd->decoder, event);
res = gst_pad_event_default (pad, event);
break;
case GST_EVENT_FLUSH_START:
gst_kate_util_decoder_base_set_flushing (&kd->decoder, TRUE);
res = gst_pad_event_default (pad, event);
break;
case GST_EVENT_FLUSH_STOP:
gst_kate_util_decoder_base_set_flushing (&kd->decoder, FALSE);
res = gst_pad_event_default (pad, event);
break;
default:
res = gst_pad_event_default (pad, event);
break;
}
gst_object_unref (kd);
return res;
}
static GstCaps *
gst_kate_dec_src_get_caps (GstPad * pad)
{
GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad)));
GstCaps *caps;
g_return_val_if_fail (kd != NULL, FALSE);
if (kd->src_caps) {
GST_DEBUG_OBJECT (kd, "We have src caps (%s)",
gst_caps_to_string (kd->src_caps));
caps = kd->src_caps;
} else {
GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps");
caps = gst_static_pad_template_get_caps (&src_factory);
}
caps = gst_caps_copy (caps);
gst_object_unref (kd);
return caps;
}

View file

@ -67,12 +67,12 @@ typedef struct _GstKateDecClass GstKateDecClass;
struct _GstKateDec
{
GstElement element;
GstKateDecoderBase decoder;
GstPad *sinkpad;
GstPad *srcpad;
GstKateDecoderBase decoder;
GstCaps *src_caps;
gboolean remove_markup;
};

View file

@ -255,11 +255,6 @@ gst_kate_parse_push_buffer (GstKateParse * parse, GstBuffer * buf,
GST_BUFFER_OFFSET_END (buf) = granulepos;
GST_BUFFER_TIMESTAMP (buf) = GST_BUFFER_OFFSET (buf);
/* Hack to flush each packet on its own page - taken off the CMML encoder element */
/* TODO: this is shite and needs to go once I find a way to tell Ogg to flush
as it messes up Matroska's track duration */
GST_BUFFER_DURATION (buf) = G_MAXINT64;
gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad));
return gst_pad_push (parse->srcpad, buf);

View file

@ -804,14 +804,6 @@ gst_kate_spu_encode_spu (GstKateDec * kd, const kate_event * ev)
bytes[nbytes++] =
((kp->colors[palette[1]].a / 17) << 4) | (kp->colors[palette[0]].a / 17);
#if 0
// move to top left - avoids a crash in dvdspu when overlaying on a small video :/
right -= left;
bottom -= top;
left = 0;
top = 0;
#endif
CHKBUFSPC (7 * 2);
bytes[nbytes++] = SPU_CMD_SET_DAREA;
bytes[nbytes++] = left >> 4;

View file

@ -88,6 +88,19 @@
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
{
@ -119,16 +132,28 @@ static GstStaticPadTemplate kate_sink_factory =
);
static GstStaticPadTemplate video_sink_factory =
GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, bpp=(int)32, depth=(int)24")
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB ", endianness = (int) 1234" ";"
GST_VIDEO_CAPS_BGRx ", endianness = (int)4321")
#else
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB ", endianness = (int) 4321" ";"
GST_VIDEO_CAPS_BGRx ", endianness = (int)1234")
#endif
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, bpp=(int)32, depth=(int)24")
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB ", endianness = (int) 1234" ";"
GST_VIDEO_CAPS_BGRx ", endianness = (int)4321")
#else
GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB ", endianness = (int) 4321" ";"
GST_VIDEO_CAPS_BGRx ", endianness = (int)1234")
#endif
);
GST_BOILERPLATE (GstKateTiger, gst_kate_tiger, GstElement, GST_TYPE_ELEMENT);
@ -163,6 +188,7 @@ 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);
@ -302,19 +328,19 @@ gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass)
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_set_query_function (tiger->videosinkpad, GST_DEBUG_FUNCPTR (gst_kate_tiger_video_sink_query));
gst_pad_use_fixed_caps (tiger->videosinkpad);
gst_pad_set_caps (tiger->videosinkpad,
gst_static_pad_template_get_caps (&video_sink_factory));
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);
gst_kate_util_decode_base_init (&tiger->decoder, FALSE);
tiger->tr = NULL;
@ -400,7 +426,7 @@ gst_kate_tiger_set_property (GObject * object, guint prop_id,
GstKateTiger *tiger = GST_KATE_TIGER (object);
const char *str;
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
switch (prop_id) {
case ARG_DEFAULT_FONT_DESC:
@ -465,7 +491,7 @@ gst_kate_tiger_set_property (GObject * object, guint prop_id,
break;
}
g_mutex_unlock (tiger->mutex);
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
}
static void
@ -474,7 +500,7 @@ gst_kate_tiger_get_property (GObject * object, guint prop_id,
{
GstKateTiger *tiger = GST_KATE_TIGER (object);
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
switch (prop_id) {
case ARG_DEFAULT_FONT_DESC:
@ -522,7 +548,7 @@ gst_kate_tiger_get_property (GObject * object, guint prop_id,
break;
}
g_mutex_unlock (tiger->mutex);
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
}
/* GstElement vmethod implementations */
@ -538,30 +564,36 @@ gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf)
const kate_event *ev = NULL;
GstFlowReturn rflow = GST_FLOW_OK;
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
GST_LOG_OBJECT (tiger, "Got kate buffer");
GST_LOG_OBJECT (tiger, "Got kate buffer, caps %s",
gst_caps_to_string (GST_BUFFER_CAPS (buf)));
rflow =
gst_kate_util_decoder_base_chain_kate_packet (&tiger->decoder,
GST_ELEMENT_CAST (tiger), pad, buf, tiger->srcpad, &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);
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);
g_mutex_unlock (tiger->mutex);
return rflow;
}
@ -569,28 +601,36 @@ static gboolean
gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps)
{
GstKateTiger *tiger = GST_KATE_TIGER (gst_pad_get_parent (pad));
GstStructure *s;
GstVideoFormat format;
gint w, h;
gboolean res = FALSE;
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
s = gst_caps_get_structure (caps, 0);
/* 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 (G_LIKELY (gst_structure_get_int (s, "width", &w))
&& G_LIKELY (gst_structure_get_int (s, "height", &h))) {
GST_INFO_OBJECT (tiger, "video sink: %d %d", w, h);
if (gst_video_format_parse_caps (caps, &format, &w, &h)) {
tiger->video_width = w;
tiger->video_height = h;
res = TRUE;
}
g_mutex_unlock (tiger->mutex);
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)
{
@ -599,10 +639,22 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
unsigned char *ptr;
int ret;
g_mutex_lock (tiger->mutex);
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)) {
@ -613,12 +665,17 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
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, 0); // TODO: stride ?
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_BUFFER_TIMESTAMP (buf) / (gdouble) GST_SECOND;
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",
@ -636,12 +693,13 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
}
}
}
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
rflow = gst_pad_push (tiger->srcpad, buf);
gst_object_unref (tiger);
g_mutex_unlock (tiger->mutex);
return rflow;
}
@ -654,12 +712,14 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state");
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
if (tiger->tr) {
tiger_renderer_destroy (tiger->tr);
tiger->tr = NULL;
}
g_mutex_unlock (tiger->mutex);
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
tiger->video_flushing = TRUE;
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
break;
default:
break;
@ -672,7 +732,7 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
GST_DEBUG_OBJECT (tiger, "READY -> PAUSED, initializing kate state");
g_mutex_lock (tiger->mutex);
GST_KATE_TIGER_MUTEX_LOCK (tiger);
if (tiger->decoder.initialized) {
int ret = tiger_renderer_create (&tiger->tr);
if (ret < 0) {
@ -692,7 +752,9 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
gst_kate_tiger_update_quality (tiger);
}
}
g_mutex_unlock (tiger->mutex);
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
tiger->video_flushing = FALSE;
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
break;
default:
break;
@ -713,18 +775,42 @@ gst_kate_tiger_seek (GstKateTiger * tiger, GstPad * pad, GstEvent * event)
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:
target = gst_kate_tiger_get_time (tiger) + cur / (float) GST_SECOND;
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)) {
if (gst_pad_push_event (tiger->katesinkpad, event)) {
if (format == GST_FORMAT_TIME) {
/* if seeking in time, we can update tiger to remove any appropriate events */
kate_float target = cur / (gdouble) GST_SECOND;
GST_INFO_OBJECT (tiger, "Seeking in time to %f", target);
g_mutex_lock (tiger->mutex);
tiger_renderer_seek (tiger->tr, target);
g_mutex_unlock (tiger->mutex);
}
int ret = gst_pad_push_event (tiger->katesinkpad, event);
if (ret) {
return TRUE;
} else {
return FALSE;
@ -744,6 +830,9 @@ gst_kate_tiger_source_event (GstPad * pad, GstEvent * event)
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");
@ -759,6 +848,49 @@ gst_kate_tiger_source_event (GstPad * pad, GstEvent * event)
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)
{
@ -768,16 +900,69 @@ gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event)
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:
GST_INFO_OBJECT (tiger, "New segment on Kate pad");
gst_event_unref (event);
{
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_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);
}
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);
@ -789,12 +974,32 @@ gst_kate_tiger_kate_event (GstPad * pad, GstEvent * event)
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;
}

View file

@ -68,14 +68,12 @@ typedef struct _GstKateTigerClass GstKateTigerClass;
struct _GstKateTiger
{
GstElement element;
GstKateDecoderBase decoder;
GstPad *katesinkpad;
GstPad *videosinkpad;
GstPad *srcpad;
GstKateDecoderBase decoder;
tiger_renderer *tr;
gdouble quality;
@ -93,8 +91,12 @@ struct _GstKateTiger
gint video_width;
gint video_height;
gboolean swap_rgb;
GMutex *mutex;
GstSegment video_segment;
gboolean video_flushing;
};
struct _GstKateTigerClass

View file

@ -23,10 +23,17 @@
# include "config.h"
#endif
#include <string.h>
#include <gst/tag/tag.h>
#include "gstkate.h"
#include "gstkateutil.h"
GST_DEBUG_CATEGORY_EXTERN (gst_kateutil_debug);
#define GST_CAT_DEFAULT gst_kateutil_debug
static void gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase *
decoder);
GstCaps *
gst_kate_util_set_header_on_caps (GstElement * element, GstCaps * caps,
GList * headers)
@ -95,7 +102,8 @@ gst_kate_util_install_decoder_base_properties (GObjectClass * gobject_class)
}
void
gst_kate_util_decode_base_init (GstKateDecoderBase * decoder)
gst_kate_util_decode_base_init (GstKateDecoderBase * decoder,
gboolean delay_events)
{
if (G_UNLIKELY (!decoder))
return;
@ -106,6 +114,8 @@ gst_kate_util_decode_base_init (GstKateDecoderBase * decoder)
decoder->original_canvas_height = 0;
decoder->tags = NULL;
decoder->initialized = FALSE;
decoder->delay_events = delay_events;
decoder->event_queue = NULL;
}
static void
@ -121,9 +131,76 @@ gst_kate_util_decode_base_reset (GstKateDecoderBase * decoder)
}
decoder->original_canvas_width = 0;
decoder->original_canvas_height = 0;
if (decoder->event_queue) {
gst_kate_util_decoder_base_free_event_queue (decoder);
}
decoder->initialized = FALSE;
}
gboolean
gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder,
GstEvent * event, gboolean (*handler) (GstPad *, GstEvent *), GstPad * pad)
{
gboolean can_be_queued;
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_START:
case GST_EVENT_FLUSH_STOP:
case GST_EVENT_EOS:
can_be_queued = FALSE;
break;
default:
can_be_queued = TRUE;
break;
}
if (decoder->delay_events && can_be_queued) {
GstKateDecoderBaseQueuedEvent *item;
GST_DEBUG_OBJECT (decoder, "We have to delay the event");
item = g_slice_new (GstKateDecoderBaseQueuedEvent);
if (item) {
item->event = event;
item->pad = pad;
item->handler = handler;
g_queue_push_tail (decoder->event_queue, item);
return TRUE;
} else {
return FALSE;
}
} else {
return FALSE;
}
}
static void
gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase * decoder)
{
while (decoder->event_queue->length) {
GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
g_queue_pop_head (decoder->event_queue);
g_slice_free (GstKateDecoderBaseQueuedEvent, item);
}
g_queue_free (decoder->event_queue);
decoder->event_queue = NULL;
}
static void
gst_kate_util_decoder_base_drain_event_queue (GstKateDecoderBase * decoder)
{
decoder->delay_events = FALSE;
if (decoder->event_queue->length == 0)
return;
GST_DEBUG_OBJECT (decoder, "We can now drain all events!");
while (decoder->event_queue->length) {
GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
g_queue_pop_head (decoder->event_queue);
(*item->handler) (item->pad, item->event);
g_slice_free (GstKateDecoderBaseQueuedEvent, item);
}
}
gboolean
gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder,
GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
@ -152,38 +229,67 @@ gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder,
GstFlowReturn
gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad,
const kate_event ** ev)
GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev)
{
kate_packet kp;
int ret;
GstFlowReturn rflow = GST_FLOW_OK;
gboolean is_header;
GST_DEBUG_OBJECT (element, "got kate packet, %u bytes, type %02x",
GST_BUFFER_SIZE (buf),
GST_BUFFER_SIZE (buf) == 0 ? -1 : GST_BUFFER_DATA (buf)[0]);
is_header = GST_BUFFER_SIZE (buf) > 0 && (GST_BUFFER_DATA (buf)[0] & 0x80);
if (!is_header && decoder->tags) {
/* after we've processed headers, send any tags before processing the data packet */
GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s",
GST_DEBUG_PAD_NAME (tagpad));
gst_element_found_tags_for_pad (element, tagpad, decoder->tags);
decoder->tags = NULL;
}
kate_packet_wrap (&kp, GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (buf));
ret = kate_high_decode_packetin (&decoder->k, &kp, ev);
if (G_UNLIKELY (ret < 0)) {
GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL),
("Failed to decode Kate packet: %d", ret));
return GST_FLOW_ERROR;
} else if (G_UNLIKELY (ret > 0)) {
}
if (G_UNLIKELY (ret > 0)) {
GST_DEBUG_OBJECT (element,
"kate_high_decode_packetin has received EOS packet");
return GST_FLOW_OK;
}
/* headers may be interesting to retrieve information from */
if (G_LIKELY (GST_BUFFER_SIZE (buf) > 0))
if (G_UNLIKELY (is_header)) {
switch (GST_BUFFER_DATA (buf)[0]) {
GstCaps *caps;
case 0x80: /* ID header */
GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s",
decoder->k.ki->language, decoder->k.ki->category);
caps = gst_caps_new_simple ("text/x-pango-markup", NULL);
gst_pad_set_caps (srcpad, caps);
gst_caps_unref (caps);
if (src_caps) {
if (*src_caps) {
gst_caps_unref (*src_caps);
*src_caps = NULL;
}
if (strcmp (decoder->k.ki->category, "K-SPU") == 0 ||
strcmp (decoder->k.ki->category, "spu-subtitles") == 0) {
*src_caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
} else if (decoder->k.ki->text_markup_type == kate_markup_none) {
*src_caps = gst_caps_new_simple ("text/plain", NULL);
} else {
*src_caps = gst_caps_new_simple ("text/x-pango-markup", NULL);
}
GST_INFO_OBJECT (element, "Setting src caps to %s",
gst_caps_to_string (*src_caps));
if (!gst_pad_set_caps (srcpad, *src_caps)) {
GST_ERROR_OBJECT (element,
"Failed to renegotiate caps for pad %s:%s",
GST_DEBUG_PAD_NAME (srcpad));
}
}
if (decoder->k.ki->language && *decoder->k.ki->language) {
GstTagList *old = decoder->tags, *tags = gst_tag_list_new ();
if (tags) {
@ -214,6 +320,9 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
decoder->original_canvas_width = decoder->k.ki->original_canvas_width;
decoder->original_canvas_height = decoder->k.ki->original_canvas_height;
/* we can now send away any event we've delayed, as the src pad now has caps */
gst_kate_util_decoder_base_drain_event_queue (decoder);
break;
case 0x81: /* Vorbis comments header */
@ -247,8 +356,9 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
if (old)
gst_tag_list_free (old);
#if 0
if (decoder->initialized) {
gst_element_found_tags_for_pad (element, srcpad, decoder->tags);
gst_element_found_tags_for_pad (element, tagpad, decoder->tags);
decoder->tags = NULL;
} else {
/* Only push them as messages for the time being. *
@ -257,12 +367,14 @@ gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
gst_message_new_tag (GST_OBJECT (element),
gst_tag_list_copy (decoder->tags)));
}
#endif
}
break;
default:
break;
}
}
return rflow;
}
@ -285,7 +397,10 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
GST_WARNING_OBJECT (element, "failed to initialize kate state: %d",
ret);
}
gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
decoder->kate_flushing = FALSE;
decoder->initialized = TRUE;
decoder->event_queue = g_queue_new ();
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@ -304,6 +419,8 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
kate_high_decode_clear (&decoder->k);
decoder->initialized = FALSE;
}
gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
decoder->kate_flushing = TRUE;
gst_kate_util_decode_base_reset (decoder);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
@ -316,6 +433,73 @@ gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
return res;
}
void
gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder,
gboolean flushing)
{
decoder->kate_flushing = flushing;
gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
}
void
gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder,
GstEvent * event)
{
gboolean update;
gdouble rate;
GstFormat format;
gint64 start, stop, time;
gdouble arate;
gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
&start, &stop, &time);
GST_DEBUG_OBJECT (decoder, "kate 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_segment_set_newsegment_full (&decoder->kate_segment, update, rate,
arate, format, start, stop, time);
}
gboolean
gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder,
GstElement * element, GstBuffer * buf)
{
gint64 clip_start = 0, clip_stop = 0;
gboolean in_seg;
if (decoder->kate_flushing) {
GST_LOG_OBJECT (element, "Kate pad flushing, buffer ignored");
return FALSE;
}
if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
GstClockTime stop;
if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf)))
stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
else
stop = GST_CLOCK_TIME_NONE;
in_seg = gst_segment_clip (&decoder->kate_segment, GST_FORMAT_TIME,
GST_BUFFER_TIMESTAMP (buf), stop, &clip_start, &clip_stop);
} else {
in_seg = TRUE;
}
if (in_seg) {
if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
gst_segment_set_last_stop (&decoder->kate_segment, GST_FORMAT_TIME,
clip_start);
}
} else {
GST_INFO_OBJECT (element, "Kate buffer not in segment, ignored");
}
return in_seg;
}
static GstClockTime
gst_kate_util_granule_time (kate_state * k, gint64 granulepos)
{

View file

@ -37,6 +37,15 @@ G_BEGIN_DECLS enum
typedef struct
{
GstEvent * event;
gboolean (*handler)(GstPad *, GstEvent *);
GstPad *pad;
} GstKateDecoderBaseQueuedEvent;
typedef struct
{
GstElement element;
kate_state k;
gboolean initialized;
@ -49,11 +58,17 @@ typedef struct
gint original_canvas_width;
gint original_canvas_height;
GstSegment kate_segment;
gboolean kate_flushing;
gboolean delay_events;
GQueue *event_queue;
} GstKateDecoderBase;
extern GstCaps *gst_kate_util_set_header_on_caps (GstElement * element,
GstCaps * caps, GList * headers);
extern void gst_kate_util_decode_base_init (GstKateDecoderBase * decoder);
extern void gst_kate_util_decode_base_init (GstKateDecoderBase * decoder,
gboolean delay_events);
extern void gst_kate_util_install_decoder_base_properties (GObjectClass *
gobject_class);
extern gboolean gst_kate_util_decoder_base_get_property (GstKateDecoderBase *
@ -62,7 +77,16 @@ extern gboolean gst_kate_util_decoder_base_get_property (GstKateDecoderBase *
extern GstFlowReturn
gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
GstElement * element, GstPad * pad, GstBuffer * buffer, GstPad * srcpad,
const kate_event ** ev);
GstPad * tagpad, GstCaps **src_caps, const kate_event ** ev);
extern void
gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder,
gboolean flushing);
extern void
gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder,
GstEvent * event);
extern gboolean
gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder,
GstElement * element, GstBuffer * buf);
extern GstStateChangeReturn
gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
GstElement * element, GstElementClass * parent_class,
@ -72,6 +96,8 @@ extern gboolean gst_kate_decoder_base_convert (GstKateDecoderBase * decoder,
GstFormat * dest_fmt, gint64 * dest_val);
extern gboolean gst_kate_decoder_base_sink_query (GstKateDecoderBase * decoder,
GstElement * element, GstPad * pad, GstQuery * query);
extern gboolean
gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder, GstEvent * event, gboolean (*handler)(GstPad *, GstEvent *), GstPad * pad);
G_END_DECLS
#endif /* __GST_KATE_UTIL_H__ */