cccombiner: Fix wrong caps and buffer ordering
If there's queued video buffer, forwards new caps event once the queued video buffer is drained. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/8473>
This commit is contained in:
parent
bd37947254
commit
cc6336c222
@ -513,6 +513,7 @@ gst_cc_combiner_collect_captions (GstCCCombiner * self, gboolean timeout)
|
||||
GstVideoTimeCodeMeta *tc_meta;
|
||||
GstVideoTimeCode *tc = NULL;
|
||||
gboolean caption_pad_is_eos = FALSE;
|
||||
GstFlowReturn flow_ret = GST_FLOW_OK;
|
||||
|
||||
g_assert (self->current_video_buffer != NULL);
|
||||
|
||||
@ -720,7 +721,18 @@ done:
|
||||
src_pad->segment.position =
|
||||
GST_BUFFER_PTS (video_buf) + GST_BUFFER_DURATION (video_buf);
|
||||
|
||||
return gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (self), video_buf);
|
||||
flow_ret =
|
||||
gst_aggregator_finish_buffer (GST_AGGREGATOR_CAST (self), video_buf);
|
||||
|
||||
if (self->pending_video_caps) {
|
||||
GST_DEBUG_OBJECT (self, "Setting pending video caps %" GST_PTR_FORMAT,
|
||||
self->pending_video_caps);
|
||||
gst_aggregator_set_src_caps (GST_AGGREGATOR_CAST (self),
|
||||
self->pending_video_caps);
|
||||
gst_clear_caps (&self->pending_video_caps);
|
||||
}
|
||||
|
||||
return flow_ret;
|
||||
}
|
||||
|
||||
static GstClockTime
|
||||
@ -946,7 +958,13 @@ gst_cc_combiner_sink_event (GstAggregator * aggregator,
|
||||
cc_buffer_set_max_buffer_time (self->cc_buffer,
|
||||
frame_duration * self->max_scheduled);
|
||||
|
||||
gst_aggregator_set_src_caps (aggregator, caps);
|
||||
if (self->current_video_buffer) {
|
||||
GST_DEBUG_OBJECT (self, "Storing new caps %" GST_PTR_FORMAT, caps);
|
||||
gst_caps_replace (&self->pending_video_caps, caps);
|
||||
} else {
|
||||
gst_clear_caps (&self->pending_video_caps);
|
||||
gst_aggregator_set_src_caps (aggregator, caps);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -982,6 +1000,7 @@ gst_cc_combiner_stop (GstAggregator * aggregator)
|
||||
self->current_video_running_time = self->current_video_running_time_end =
|
||||
self->previous_video_running_time_end = GST_CLOCK_TIME_NONE;
|
||||
gst_buffer_replace (&self->current_video_buffer, NULL);
|
||||
gst_clear_caps (&self->pending_video_caps);
|
||||
|
||||
g_array_set_size (self->current_frame_captions, 0);
|
||||
self->caption_type = GST_VIDEO_CAPTION_TYPE_UNKNOWN;
|
||||
@ -1002,6 +1021,7 @@ gst_cc_combiner_flush (GstAggregator * aggregator)
|
||||
self->current_video_running_time = self->current_video_running_time_end =
|
||||
self->previous_video_running_time_end = GST_CLOCK_TIME_NONE;
|
||||
gst_buffer_replace (&self->current_video_buffer, NULL);
|
||||
gst_clear_caps (&self->pending_video_caps);
|
||||
|
||||
g_array_set_size (self->current_frame_captions, 0);
|
||||
|
||||
|
@ -72,6 +72,7 @@ struct _GstCCCombiner
|
||||
GstClockTime current_video_running_time;
|
||||
GstClockTime current_video_running_time_end;
|
||||
GstBuffer *current_video_buffer;
|
||||
GstCaps *pending_video_caps;
|
||||
|
||||
GArray *current_frame_captions;
|
||||
GstVideoCaptionType caption_type;
|
||||
|
@ -423,6 +423,183 @@ GST_START_TEST (captions_50fps_to_25fps)
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
guint num_buffers;
|
||||
gboolean got_custom_event;
|
||||
gboolean got_eos;
|
||||
} CapsChangeData;
|
||||
|
||||
static GstPadProbeReturn
|
||||
video_caps_change_probe (GstPad * pad, GstPadProbeInfo * info,
|
||||
CapsChangeData * data)
|
||||
{
|
||||
g_mutex_lock (&data->lock);
|
||||
if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
|
||||
GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
|
||||
switch (GST_EVENT_TYPE (ev)) {
|
||||
case GST_EVENT_CUSTOM_DOWNSTREAM:
|
||||
data->got_custom_event = TRUE;
|
||||
g_cond_signal (&data->cond);
|
||||
break;
|
||||
case GST_EVENT_CAPS:
|
||||
{
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
const gchar *name;
|
||||
|
||||
gst_event_parse_caps (ev, &caps);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
name = gst_structure_get_name (s);
|
||||
|
||||
if (data->num_buffers == 0) {
|
||||
fail_unless_equals_string (name, "test/foo");
|
||||
} else {
|
||||
fail_unless_equals_string (name, "test/bar");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GST_EVENT_EOS:
|
||||
data->got_eos = TRUE;
|
||||
g_cond_signal (&data->cond);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (GST_IS_BUFFER (GST_PAD_PROBE_INFO_DATA (info))) {
|
||||
data->num_buffers++;
|
||||
}
|
||||
g_mutex_unlock (&data->lock);
|
||||
|
||||
return GST_PAD_PROBE_DROP;
|
||||
}
|
||||
|
||||
GST_START_TEST (video_caps_change)
|
||||
{
|
||||
GstBuffer *buf;
|
||||
GstPad *sinkpad;
|
||||
GstPad *caption_pad;
|
||||
GstPad *srcpad;
|
||||
GstCaps *caps;
|
||||
const guint8 cc_data[3] = { 0xfc, 0x20, 0x20 };
|
||||
GstEvent *event;
|
||||
CapsChangeData data;
|
||||
GstElement *elem;
|
||||
GstSegment segment;
|
||||
GstFlowReturn flow_ret;
|
||||
gboolean ret;
|
||||
|
||||
g_mutex_init (&data.lock);
|
||||
g_cond_init (&data.cond);
|
||||
data.num_buffers = 0;
|
||||
data.got_custom_event = FALSE;
|
||||
data.got_eos = FALSE;
|
||||
|
||||
elem = gst_element_factory_make ("cccombiner", NULL);
|
||||
|
||||
g_object_set (elem, "schedule", FALSE, "output-padding", FALSE, NULL);
|
||||
|
||||
sinkpad = gst_element_get_static_pad (elem, "sink");
|
||||
srcpad = gst_element_get_static_pad (elem, "src");
|
||||
caption_pad = gst_element_request_pad_simple (elem, "caption");
|
||||
|
||||
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
|
||||
(GstPadProbeCallback) video_caps_change_probe, &data, NULL);
|
||||
|
||||
gst_element_set_state (elem, GST_STATE_PLAYING);
|
||||
|
||||
/* Send mandatory events */
|
||||
gst_pad_send_event (sinkpad, gst_event_new_stream_start ("test-start-0"));
|
||||
gst_pad_send_event (caption_pad, gst_event_new_stream_start ("test-start-1"));
|
||||
|
||||
caps = gst_caps_from_string ("test/foo");
|
||||
fail_unless (caps);
|
||||
gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
caps = gst_caps_from_string (cea708_cc_data_caps.string);
|
||||
fail_unless (caps);
|
||||
gst_pad_send_event (caption_pad, gst_event_new_caps (caps));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
gst_segment_init (&segment, GST_FORMAT_TIME);
|
||||
gst_pad_send_event (sinkpad, gst_event_new_segment (&segment));
|
||||
gst_pad_send_event (caption_pad, gst_event_new_segment (&segment));
|
||||
|
||||
/* Push a video buffer */
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 0;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
flow_ret = gst_pad_chain (sinkpad, buf);
|
||||
fail_unless (flow_ret == GST_FLOW_OK);
|
||||
|
||||
/* Push a gap event. aggregate() will consume this event
|
||||
* and cccombiner will hold the first video buffer without pushing
|
||||
* to downstream */
|
||||
event = gst_event_new_gap (0, 40 * GST_MSECOND - 1);
|
||||
ret = gst_pad_send_event (caption_pad, event);
|
||||
fail_unless (ret);
|
||||
|
||||
/* Send a serialized event to ensure aggregate() got called */
|
||||
event = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM,
|
||||
gst_structure_new_empty ("test-caps-serialize"));
|
||||
ret = gst_pad_send_event (caption_pad, event);
|
||||
fail_unless (ret);
|
||||
|
||||
g_mutex_lock (&data.lock);
|
||||
while (!data.got_custom_event)
|
||||
g_cond_wait (&data.cond, &data.lock);
|
||||
|
||||
/* there should no buffer pushed at this point */
|
||||
fail_unless (data.num_buffers == 0);
|
||||
g_mutex_unlock (&data.lock);
|
||||
|
||||
/* Push new caps with buffers */
|
||||
caps = gst_caps_new_empty_simple ("test/bar");
|
||||
gst_pad_send_event (sinkpad, gst_event_new_caps (caps));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
flow_ret = gst_pad_chain (sinkpad, buf);
|
||||
fail_unless (flow_ret == GST_FLOW_OK);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (3);
|
||||
gst_buffer_fill (buf, 0, cc_data, 3);
|
||||
GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
flow_ret = gst_pad_chain (caption_pad, buf);
|
||||
fail_unless (flow_ret == GST_FLOW_OK);
|
||||
|
||||
ret = gst_pad_send_event (sinkpad, gst_event_new_eos ());
|
||||
fail_unless (ret);
|
||||
ret = gst_pad_send_event (caption_pad, gst_event_new_eos ());
|
||||
fail_unless (ret);
|
||||
|
||||
g_mutex_lock (&data.lock);
|
||||
while (!data.got_eos)
|
||||
g_cond_wait (&data.cond, &data.lock);
|
||||
|
||||
fail_unless_equals_int (data.num_buffers, 2);
|
||||
g_mutex_unlock (&data.lock);
|
||||
|
||||
gst_element_set_state (elem, GST_STATE_NULL);
|
||||
gst_object_unref (sinkpad);
|
||||
gst_object_unref (srcpad);
|
||||
gst_element_release_request_pad (elem, caption_pad);
|
||||
gst_object_unref (caption_pad);
|
||||
gst_object_unref (elem);
|
||||
|
||||
g_mutex_clear (&data.lock);
|
||||
g_cond_clear (&data.cond);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static Suite *
|
||||
cccombiner_suite (void)
|
||||
{
|
||||
@ -435,6 +612,7 @@ cccombiner_suite (void)
|
||||
tcase_add_test (tc, captions_and_eos);
|
||||
tcase_add_test (tc, captions_no_output_padding_60fps_608_field1_only);
|
||||
tcase_add_test (tc, captions_50fps_to_25fps);
|
||||
tcase_add_test (tc, video_caps_change);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user