summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <michael.drake@codethink.co.uk>2018-07-18 11:11:17 +0100
committerJan Schmidt <jan@centricular.com>2018-08-14 23:00:34 +1000
commitbba33533ab589e254d2427036befec1493eca306 (patch)
tree190a7c3c23af178c93bec9777d9282d3b45744ff
parentb2d5c1ed3c7259f17e7acc0c22c3561077b39079 (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.c156
-rw-r--r--ext/assrender/gstassrender.h2
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;