kate: ensure the kate pad does not shoot ahead of the video pad

Sync both pads by waiting in the kate chain function.
Do not reset our internal segment from segment updates, in order
to be able to map video running time to kate running time, to
give libtiger the timestamp it expects. This allows us to use
running time to sync to video, which is The Right Way.

https://bugzilla.gnome.org/show_bug.cgi?id=600929
This commit is contained in:
Vincent Penquerc'h 2011-01-12 16:39:22 +00:00 committed by Tim-Philipp Müller
parent b55775a9d3
commit 0b790b663c
3 changed files with 57 additions and 4 deletions

View file

@ -309,6 +309,7 @@ gst_kate_tiger_init (GstKateTiger * tiger, GstKateTigerClass * gclass)
GST_DEBUG_OBJECT (tiger, "gst_kate_tiger_init"); GST_DEBUG_OBJECT (tiger, "gst_kate_tiger_init");
tiger->mutex = g_mutex_new (); tiger->mutex = g_mutex_new ();
tiger->cond = g_cond_new ();
tiger->katesinkpad = tiger->katesinkpad =
gst_pad_new_from_static_template (&kate_sink_factory, "subtitle_sink"); gst_pad_new_from_static_template (&kate_sink_factory, "subtitle_sink");
@ -371,6 +372,9 @@ gst_kate_tiger_dispose (GObject * object)
tiger->default_font_desc = NULL; tiger->default_font_desc = NULL;
} }
g_cond_free (tiger->cond);
tiger->cond = NULL;
g_mutex_free (tiger->mutex); g_mutex_free (tiger->mutex);
tiger->mutex = NULL; tiger->mutex = NULL;
@ -631,6 +635,34 @@ gst_kate_tiger_kate_chain (GstPad * pad, GstBuffer * buf)
gst_object_unref (tagpad); gst_object_unref (tagpad);
} }
/* we want to avoid shooting ahead of the video stream, or we will
get segment updates which will place us ahead of it, and we won't
be able to convert a video timestamp back into a kate timestamp */
if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
while (1) {
gint64 kate_time, video_time;
kate_time =
gst_segment_to_running_time (&tiger->decoder.kate_segment,
GST_FORMAT_TIME, GST_BUFFER_TIMESTAMP (buf));
video_time =
gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME,
tiger->video_segment.last_stop);
GST_DEBUG_OBJECT (tiger, "Kate time %.2f, video time %.2f (kts %ld)",
kate_time / (float) GST_SECOND, video_time / (float) GST_SECOND,
(long) GST_BUFFER_TIMESTAMP (buf));
if (kate_time <= video_time) {
break;
}
GST_LOG_OBJECT (tiger, "Waiting to return from chain function");
g_cond_wait (tiger->cond, tiger->mutex);
if (tiger->decoder.kate_flushing) {
GST_DEBUG_OBJECT (tiger, "Flushing while waiting");
break;
}
GST_LOG_OBJECT (tiger, "Woken up, checking time again");
}
}
GST_KATE_TIGER_MUTEX_UNLOCK (tiger); GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
gst_object_unref (tiger); gst_object_unref (tiger);
@ -669,8 +701,13 @@ gst_kate_tiger_video_set_caps (GstPad * pad, GstCaps * caps)
static gdouble static gdouble
gst_kate_tiger_get_time (GstKateTiger * tiger) gst_kate_tiger_get_time (GstKateTiger * tiger)
{ {
return gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME, gint64 rt =
tiger->video_segment.last_stop) / (gdouble) GST_SECOND; gst_segment_to_running_time (&tiger->video_segment, GST_FORMAT_TIME,
tiger->video_segment.last_stop);
gint64 pos =
gst_segment_to_position (&tiger->decoder.kate_segment, GST_FORMAT_TIME,
rt);
return pos / (gdouble) GST_SECOND;
} }
static GstFlowReturn static GstFlowReturn
@ -695,6 +732,7 @@ gst_kate_tiger_video_chain (GstPad * pad, GstBuffer * buf)
if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) { if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
gst_segment_set_last_stop (&tiger->video_segment, GST_FORMAT_TIME, gst_segment_set_last_stop (&tiger->video_segment, GST_FORMAT_TIME,
GST_BUFFER_TIMESTAMP (buf)); GST_BUFFER_TIMESTAMP (buf));
g_cond_broadcast (tiger->cond);
} }
/* draw on it */ /* draw on it */
@ -755,6 +793,8 @@ gst_kate_tiger_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state"); GST_DEBUG_OBJECT (tiger, "PAUSED -> READY, clearing kate state");
GST_KATE_TIGER_MUTEX_LOCK (tiger); GST_KATE_TIGER_MUTEX_LOCK (tiger);
gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
g_cond_broadcast (tiger->cond);
if (tiger->tr) { if (tiger->tr) {
tiger_renderer_destroy (tiger->tr); tiger_renderer_destroy (tiger->tr);
tiger->tr = NULL; tiger->tr = NULL;
@ -904,6 +944,7 @@ gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event)
case GST_EVENT_NEWSEGMENT: case GST_EVENT_NEWSEGMENT:
GST_INFO_OBJECT (tiger, "New segment on Kate pad"); GST_INFO_OBJECT (tiger, "New segment on Kate pad");
GST_KATE_TIGER_MUTEX_LOCK (tiger); GST_KATE_TIGER_MUTEX_LOCK (tiger);
g_cond_broadcast (tiger->cond);
gst_kate_util_decoder_base_new_segment_event (&tiger->decoder, event); gst_kate_util_decoder_base_new_segment_event (&tiger->decoder, event);
GST_KATE_TIGER_MUTEX_UNLOCK (tiger); GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
gst_event_unref (event); gst_event_unref (event);
@ -912,6 +953,7 @@ gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event)
GST_KATE_TIGER_MUTEX_LOCK (tiger); GST_KATE_TIGER_MUTEX_LOCK (tiger);
gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE); gst_kate_util_decoder_base_set_flushing (&tiger->decoder, TRUE);
GST_KATE_TIGER_MUTEX_UNLOCK (tiger); GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
g_cond_broadcast (tiger->cond);
gst_event_unref (event); gst_event_unref (event);
break; break;
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP:
@ -924,6 +966,9 @@ gst_kate_tiger_handle_kate_event (GstPad * pad, GstEvent * event)
/* we ignore this, it just means we don't have anymore Kate packets, but /* 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 */ the Tiger renderer will still draw (if appropriate) on incoming video */
GST_INFO_OBJECT (tiger, "EOS on Kate pad"); GST_INFO_OBJECT (tiger, "EOS on Kate pad");
GST_KATE_TIGER_MUTEX_LOCK (tiger);
g_cond_broadcast (tiger->cond);
GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
gst_event_unref (event); gst_event_unref (event);
break; break;
default: default:
@ -1000,6 +1045,7 @@ gst_kate_tiger_handle_video_event (GstPad * pad, GstEvent * event)
gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED); gst_segment_init (&tiger->video_segment, GST_FORMAT_UNDEFINED);
tiger->video_flushing = TRUE; tiger->video_flushing = TRUE;
GST_KATE_TIGER_MUTEX_UNLOCK (tiger); GST_KATE_TIGER_MUTEX_UNLOCK (tiger);
g_cond_broadcast (tiger->cond);
res = gst_pad_event_default (pad, event); res = gst_pad_event_default (pad, event);
break; break;
case GST_EVENT_FLUSH_STOP: case GST_EVENT_FLUSH_STOP:

View file

@ -94,6 +94,7 @@ struct _GstKateTiger
gboolean swap_rgb; gboolean swap_rgb;
GMutex *mutex; GMutex *mutex;
GCond *cond;
GstSegment video_segment; GstSegment video_segment;
gboolean video_flushing; gboolean video_flushing;

View file

@ -454,8 +454,14 @@ gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder,
" %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT, " %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT,
update, rate, arate, format, GST_TIME_ARGS (start), update, rate, arate, format, GST_TIME_ARGS (start),
GST_TIME_ARGS (stop), GST_TIME_ARGS (time)); GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
if (!update) {
/* Tiger uses this segment is used to remap the video running time to the
Kate running time. The sending of segment updates to keep streams in sync
does kinda rain on our parade though, and since we don't need these,
we just ignore those here */
gst_segment_set_newsegment_full (&decoder->kate_segment, update, rate, gst_segment_set_newsegment_full (&decoder->kate_segment, update, rate,
arate, format, start, stop, time); arate, format, start, stop, time);
}
} }
gboolean gboolean