diff options
author | Michael Drake <michael.drake@codethink.co.uk> | 2018-07-18 11:11:17 +0100 |
---|---|---|
committer | Jan Schmidt <jan@centricular.com> | 2018-08-14 23:00:34 +1000 |
commit | bba33533ab589e254d2427036befec1493eca306 (patch) | |
tree | 190a7c3c23af178c93bec9777d9282d3b45744ff | |
parent | b2d5c1ed3c7259f17e7acc0c22c3561077b39079 (diff) |
assrender: fix multiple subtitles on screen simultaneously
This fixes an issue with SSA/ASS subtitles, where subtitles
would fail to appear if there was already a subtitle on screen.
This was because `struct _GstAssRender` had a single
`GstBuffer *subtitle_pending` member. This meant that
the assrender context could only be aware of one subtitle
at a time.
This patch changes the subtitle_pending member to a
linked list of pending subtitles.
The `gst_ass_render_chain_text` function no longer needs
to care about whether there are already subtitles pending,
it simply appends new subtitles to the list.
The `gst_ass_render_chain_video` function has been modified
to handle the list of pending subtitles.
Finally, the `gst_ass_render_pop_text` function has been
modified to pop the entire list of pending subtitles.
https://bugzilla.gnome.org/show_bug.cgi?id=735944
-rw-r--r-- | ext/assrender/gstassrender.c | 156 | ||||
-rw-r--r-- | ext/assrender/gstassrender.h | 2 |
2 files changed, 90 insertions, 68 deletions
diff --git a/ext/assrender/gstassrender.c b/ext/assrender/gstassrender.c index 07e33d452..463ebafcd 100644 --- a/ext/assrender/gstassrender.c +++ b/ext/assrender/gstassrender.c @@ -356,11 +356,13 @@ gst_ass_render_get_property (GObject * object, guint prop_id, static void gst_ass_render_pop_text (GstAssRender * render) { - if (render->subtitle_pending) { + while (render->subtitle_pending) { GST_DEBUG_OBJECT (render, "releasing text buffer %p", render->subtitle_pending); - gst_buffer_unref (render->subtitle_pending); - render->subtitle_pending = NULL; + gst_buffer_unref (render->subtitle_pending->data); + render->subtitle_pending = + g_slist_remove_link (render->subtitle_pending, + render->subtitle_pending); } /* Let the text task know we used that buffer */ @@ -1235,6 +1237,7 @@ wait_for_text_buf: if (render->renderer_init_ok && render->track_init_ok && render->enable) { /* Text pad linked, check if we have a text buffer queued */ if (render->subtitle_pending) { + GSList *subtitle_pending = render->subtitle_pending; GstClockTime text_start = GST_CLOCK_TIME_NONE; GstClockTime text_end = GST_CLOCK_TIME_NONE; GstClockTime text_running_time = GST_CLOCK_TIME_NONE; @@ -1243,20 +1246,6 @@ wait_for_text_buf: gdouble timestamp; gint changed = 0; - /* if the text buffer isn't stamped right, pop it off the - * queue and display it for the current video frame only */ - if (!GST_BUFFER_TIMESTAMP_IS_VALID (render->subtitle_pending) || - !GST_BUFFER_DURATION_IS_VALID (render->subtitle_pending)) { - GST_WARNING_OBJECT (render, - "Got text buffer with invalid timestamp or duration"); - gst_ass_render_pop_text (render); - GST_ASS_RENDER_UNLOCK (render); - goto wait_for_text_buf; - } - - text_start = GST_BUFFER_TIMESTAMP (render->subtitle_pending); - text_end = text_start + GST_BUFFER_DURATION (render->subtitle_pending); - vid_running_time = gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME, start); @@ -1264,33 +1253,63 @@ wait_for_text_buf: gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME, stop); - /* If timestamp and duration are valid */ - text_running_time = - gst_segment_to_running_time (&render->video_segment, - GST_FORMAT_TIME, text_start); - text_running_time_end = - gst_segment_to_running_time (&render->video_segment, - GST_FORMAT_TIME, text_end); - - GST_LOG_OBJECT (render, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (text_running_time), - GST_TIME_ARGS (text_running_time_end)); - GST_LOG_OBJECT (render, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, - GST_TIME_ARGS (vid_running_time), - GST_TIME_ARGS (vid_running_time_end)); - - /* Text too old */ - if (text_running_time_end <= vid_running_time) { - GST_DEBUG_OBJECT (render, "text buffer too old, popping"); - gst_ass_render_pop_text (render); - GST_ASS_RENDER_UNLOCK (render); - goto wait_for_text_buf; + while (subtitle_pending != NULL) { + + /* if the text buffer isn't stamped right, pop it off the + * queue and display it for the current video frame only */ + if (!GST_BUFFER_TIMESTAMP_IS_VALID (subtitle_pending->data) || + !GST_BUFFER_DURATION_IS_VALID (subtitle_pending->data)) { + GSList *bad = subtitle_pending; + GST_WARNING_OBJECT (render, + "Got text buffer with invalid timestamp or duration"); + gst_buffer_unref (bad->data); + subtitle_pending = bad->next; + render->subtitle_pending = + g_slist_remove_link (render->subtitle_pending, bad); + GST_ASS_RENDER_BROADCAST (render); + continue; + } + + text_start = GST_BUFFER_TIMESTAMP (subtitle_pending->data); + text_end = text_start + GST_BUFFER_DURATION (subtitle_pending->data); + + /* If timestamp and duration are valid */ + text_running_time = + gst_segment_to_running_time (&render->video_segment, + GST_FORMAT_TIME, text_start); + text_running_time_end = + gst_segment_to_running_time (&render->video_segment, + GST_FORMAT_TIME, text_end); + + GST_LOG_OBJECT (render, "T: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (text_running_time), + GST_TIME_ARGS (text_running_time_end)); + GST_LOG_OBJECT (render, "V: %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT, + GST_TIME_ARGS (vid_running_time), + GST_TIME_ARGS (vid_running_time_end)); + + /* Text too old */ + if (text_running_time_end <= vid_running_time) { + GSList *old = subtitle_pending; + GST_DEBUG_OBJECT (render, "text buffer too old, popping"); + gst_buffer_unref (old->data); + subtitle_pending = old->next; + render->subtitle_pending = + g_slist_remove_link (render->subtitle_pending, old); + GST_ASS_RENDER_BROADCAST (render); + continue; + } + + if (render->need_process) { + GST_DEBUG_OBJECT (render, "process text buffer"); + gst_ass_render_process_text (render, subtitle_pending->data, + text_running_time, text_running_time_end - text_running_time); + } + + subtitle_pending = subtitle_pending->next; } if (render->need_process) { - GST_DEBUG_OBJECT (render, "process text buffer"); - gst_ass_render_process_text (render, render->subtitle_pending, - text_running_time, text_running_time_end - text_running_time); render->need_process = FALSE; } @@ -1320,10 +1339,33 @@ wait_for_text_buf: /* Push the video frame */ ret = gst_ass_render_push_frame (render, buffer); - if (text_running_time_end <= vid_running_time_end) { - GST_ASS_RENDER_LOCK (render); - gst_ass_render_pop_text (render); - GST_ASS_RENDER_UNLOCK (render); + subtitle_pending = render->subtitle_pending; + while (subtitle_pending != NULL) { + + text_start = GST_BUFFER_TIMESTAMP (subtitle_pending->data); + text_end = text_start + GST_BUFFER_DURATION (subtitle_pending->data); + + text_running_time_end = + gst_segment_to_running_time (&render->video_segment, + GST_FORMAT_TIME, text_end); + + if (text_running_time_end <= vid_running_time_end) { + GSList *old = subtitle_pending; + GST_DEBUG_OBJECT (render, "finished text buffer, popping"); + GST_ASS_RENDER_LOCK (render); + gst_buffer_unref (old->data); + subtitle_pending = old->next; + render->subtitle_pending = + g_slist_remove_link (render->subtitle_pending, old); + GST_ASS_RENDER_BROADCAST (render); + GST_ASS_RENDER_UNLOCK (render); + render->need_process = TRUE; + if (g_slist_length (render->subtitle_pending) == 0) { + render->need_process = FALSE; + } + } else { + subtitle_pending = subtitle_pending->next; + } } } else { gboolean wait_for_text_buf = TRUE; @@ -1465,34 +1507,14 @@ gst_ass_render_chain_text (GstPad * pad, GstObject * parent, GstBuffer * buffer) else if (GST_BUFFER_DURATION_IS_VALID (buffer)) GST_BUFFER_DURATION (buffer) = clip_stop - clip_start; - if (render->subtitle_pending - && (!GST_BUFFER_TIMESTAMP_IS_VALID (render->subtitle_pending) - || !GST_BUFFER_DURATION_IS_VALID (render->subtitle_pending))) { - gst_buffer_unref (render->subtitle_pending); - render->subtitle_pending = NULL; - GST_ASS_RENDER_BROADCAST (render); - } else { - /* Wait for the previous buffer to go away */ - while (render->subtitle_pending != NULL) { - GST_DEBUG ("Pad %s:%s has a buffer queued, waiting", - GST_DEBUG_PAD_NAME (pad)); - GST_ASS_RENDER_WAIT (render); - GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad)); - if (render->subtitle_flushing) { - GST_ASS_RENDER_UNLOCK (render); - ret = GST_FLOW_FLUSHING; - goto beach; - } - } - } - if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) render->subtitle_segment.position = clip_start; GST_DEBUG_OBJECT (render, "New buffer arrived for timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); - render->subtitle_pending = gst_buffer_ref (buffer); + render->subtitle_pending = g_slist_append (render->subtitle_pending, + gst_buffer_ref (buffer)); render->need_process = TRUE; /* in case the video chain is waiting for a text buffer, wake it up */ diff --git a/ext/assrender/gstassrender.h b/ext/assrender/gstassrender.h index 42f74a042..0a03b6ab5 100644 --- a/ext/assrender/gstassrender.h +++ b/ext/assrender/gstassrender.h @@ -67,7 +67,7 @@ struct _GstAssRender GstVideoInfo info; - GstBuffer *subtitle_pending; + GSList *subtitle_pending; gboolean subtitle_flushing; gboolean subtitle_eos; GstSegment subtitle_segment; |