mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 07:08:23 +00:00
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
This commit is contained in:
parent
b2d5c1ed3c
commit
bba33533ab
2 changed files with 88 additions and 66 deletions
|
@ -356,11 +356,13 @@ gst_ass_render_get_property (GObject * object, guint prop_id,
|
||||||
static void
|
static void
|
||||||
gst_ass_render_pop_text (GstAssRender * render)
|
gst_ass_render_pop_text (GstAssRender * render)
|
||||||
{
|
{
|
||||||
if (render->subtitle_pending) {
|
while (render->subtitle_pending) {
|
||||||
GST_DEBUG_OBJECT (render, "releasing text buffer %p",
|
GST_DEBUG_OBJECT (render, "releasing text buffer %p",
|
||||||
render->subtitle_pending);
|
render->subtitle_pending);
|
||||||
gst_buffer_unref (render->subtitle_pending);
|
gst_buffer_unref (render->subtitle_pending->data);
|
||||||
render->subtitle_pending = NULL;
|
render->subtitle_pending =
|
||||||
|
g_slist_remove_link (render->subtitle_pending,
|
||||||
|
render->subtitle_pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Let the text task know we used that buffer */
|
/* 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) {
|
if (render->renderer_init_ok && render->track_init_ok && render->enable) {
|
||||||
/* Text pad linked, check if we have a text buffer queued */
|
/* Text pad linked, check if we have a text buffer queued */
|
||||||
if (render->subtitle_pending) {
|
if (render->subtitle_pending) {
|
||||||
|
GSList *subtitle_pending = render->subtitle_pending;
|
||||||
GstClockTime text_start = GST_CLOCK_TIME_NONE;
|
GstClockTime text_start = GST_CLOCK_TIME_NONE;
|
||||||
GstClockTime text_end = GST_CLOCK_TIME_NONE;
|
GstClockTime text_end = GST_CLOCK_TIME_NONE;
|
||||||
GstClockTime text_running_time = GST_CLOCK_TIME_NONE;
|
GstClockTime text_running_time = GST_CLOCK_TIME_NONE;
|
||||||
|
@ -1243,20 +1246,6 @@ wait_for_text_buf:
|
||||||
gdouble timestamp;
|
gdouble timestamp;
|
||||||
gint changed = 0;
|
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 =
|
vid_running_time =
|
||||||
gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME,
|
gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME,
|
||||||
start);
|
start);
|
||||||
|
@ -1264,6 +1253,26 @@ wait_for_text_buf:
|
||||||
gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME,
|
gst_segment_to_running_time (&render->video_segment, GST_FORMAT_TIME,
|
||||||
stop);
|
stop);
|
||||||
|
|
||||||
|
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 */
|
/* If timestamp and duration are valid */
|
||||||
text_running_time =
|
text_running_time =
|
||||||
gst_segment_to_running_time (&render->video_segment,
|
gst_segment_to_running_time (&render->video_segment,
|
||||||
|
@ -1281,16 +1290,26 @@ wait_for_text_buf:
|
||||||
|
|
||||||
/* Text too old */
|
/* Text too old */
|
||||||
if (text_running_time_end <= vid_running_time) {
|
if (text_running_time_end <= vid_running_time) {
|
||||||
|
GSList *old = subtitle_pending;
|
||||||
GST_DEBUG_OBJECT (render, "text buffer too old, popping");
|
GST_DEBUG_OBJECT (render, "text buffer too old, popping");
|
||||||
gst_ass_render_pop_text (render);
|
gst_buffer_unref (old->data);
|
||||||
GST_ASS_RENDER_UNLOCK (render);
|
subtitle_pending = old->next;
|
||||||
goto wait_for_text_buf;
|
render->subtitle_pending =
|
||||||
|
g_slist_remove_link (render->subtitle_pending, old);
|
||||||
|
GST_ASS_RENDER_BROADCAST (render);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render->need_process) {
|
if (render->need_process) {
|
||||||
GST_DEBUG_OBJECT (render, "process text buffer");
|
GST_DEBUG_OBJECT (render, "process text buffer");
|
||||||
gst_ass_render_process_text (render, render->subtitle_pending,
|
gst_ass_render_process_text (render, subtitle_pending->data,
|
||||||
text_running_time, text_running_time_end - text_running_time);
|
text_running_time, text_running_time_end - text_running_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
subtitle_pending = subtitle_pending->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render->need_process) {
|
||||||
render->need_process = FALSE;
|
render->need_process = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1320,10 +1339,33 @@ wait_for_text_buf:
|
||||||
/* Push the video frame */
|
/* Push the video frame */
|
||||||
ret = gst_ass_render_push_frame (render, buffer);
|
ret = gst_ass_render_push_frame (render, buffer);
|
||||||
|
|
||||||
|
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) {
|
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_ASS_RENDER_LOCK (render);
|
||||||
gst_ass_render_pop_text (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);
|
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 {
|
} else {
|
||||||
gboolean wait_for_text_buf = TRUE;
|
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))
|
else if (GST_BUFFER_DURATION_IS_VALID (buffer))
|
||||||
GST_BUFFER_DURATION (buffer) = clip_stop - clip_start;
|
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))
|
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
|
||||||
render->subtitle_segment.position = clip_start;
|
render->subtitle_segment.position = clip_start;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (render,
|
GST_DEBUG_OBJECT (render,
|
||||||
"New buffer arrived for timestamp %" GST_TIME_FORMAT,
|
"New buffer arrived for timestamp %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
|
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;
|
render->need_process = TRUE;
|
||||||
|
|
||||||
/* in case the video chain is waiting for a text buffer, wake it up */
|
/* in case the video chain is waiting for a text buffer, wake it up */
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct _GstAssRender
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
|
|
||||||
GstBuffer *subtitle_pending;
|
GSList *subtitle_pending;
|
||||||
gboolean subtitle_flushing;
|
gboolean subtitle_flushing;
|
||||||
gboolean subtitle_eos;
|
gboolean subtitle_eos;
|
||||||
GstSegment subtitle_segment;
|
GstSegment subtitle_segment;
|
||||||
|
|
Loading…
Reference in a new issue