mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
cccombiner: implement scheduling
Prior to that, cccombiner's behaviour was essentially that of a funnel: it strictly looked at input timestamps to associate together video and caption buffers. This patch instead exposes a "schedule" property, with a default of TRUE, to control whether caption buffers should be smoothly scheduled, in order to have exactly one per output video buffer. This can involve rewriting input captions, for example when the input is CDP sequence counters are rewritten, time codes are dropped and potentially re-injected if the input video frame had a time code meta. Caption buffers may also get split up in order to assign captions to the correct field when the input is interlaced. This can also imply that the input will drift from synchronization, when there isn't enough padding in the input stream to catch up. In that case the element will start dropping old caption buffers once the number of buffers in its internal queue reaches a certain limit (configurable). The property is exposed so that existing users of cccombiner can revert back to the original behaviour, but should eventually be removed, as that behaviour was simply inadequate. This commit also disallows changing the input caption type, as this would needlessly complicate implementation, and removes the corresponding test. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2076>
This commit is contained in:
parent
80792e12d4
commit
08442cc792
4 changed files with 919 additions and 114 deletions
|
@ -3318,7 +3318,34 @@
|
|||
"type": "GstAggregatorPad"
|
||||
}
|
||||
},
|
||||
"properties": {},
|
||||
"properties": {
|
||||
"max-scheduled": {
|
||||
"blurb": "Maximum number of buffers to queue for scheduling",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "0",
|
||||
"max": "-1",
|
||||
"min": "0",
|
||||
"mutable": "ready",
|
||||
"readable": true,
|
||||
"type": "guint",
|
||||
"writable": true
|
||||
},
|
||||
"schedule": {
|
||||
"blurb": "Schedule caption buffers so that exactly one is output per video frame",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
"controllable": false,
|
||||
"default": "true",
|
||||
"mutable": "ready",
|
||||
"readable": true,
|
||||
"type": "gboolean",
|
||||
"writable": true
|
||||
}
|
||||
},
|
||||
"rank": "none"
|
||||
},
|
||||
"ccconverter": {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,18 +40,38 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstCCCombiner GstCCCombiner;
|
||||
typedef struct _GstCCCombinerClass GstCCCombinerClass;
|
||||
|
||||
struct cdp_fps_entry
|
||||
{
|
||||
guint8 fps_idx;
|
||||
guint fps_n, fps_d;
|
||||
guint max_cc_count;
|
||||
guint max_ccp_count;
|
||||
guint max_cea608_count;
|
||||
};
|
||||
|
||||
struct _GstCCCombiner
|
||||
{
|
||||
GstAggregator parent;
|
||||
|
||||
gint video_fps_n, video_fps_d;
|
||||
gboolean progressive;
|
||||
GstClockTime previous_video_running_time_end;
|
||||
GstClockTime current_video_running_time;
|
||||
GstClockTime current_video_running_time_end;
|
||||
GstBuffer *current_video_buffer;
|
||||
|
||||
GArray *current_frame_captions;
|
||||
GstVideoCaptionType current_caption_type;
|
||||
GstVideoCaptionType caption_type;
|
||||
|
||||
gboolean prop_schedule;
|
||||
guint prop_max_scheduled;
|
||||
|
||||
gboolean schedule;
|
||||
guint max_scheduled;
|
||||
/* One queue per field */
|
||||
GstQueueArray *scheduled[2];
|
||||
guint16 cdp_hdr_sequence_cntr;
|
||||
const struct cdp_fps_entry *cdp_fps_entry;
|
||||
};
|
||||
|
||||
struct _GstCCCombinerClass
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
static GstStaticCaps foo_bar_caps = GST_STATIC_CAPS ("foo/bar");
|
||||
static GstStaticCaps cea708_cc_data_caps =
|
||||
GST_STATIC_CAPS ("closedcaption/x-cea-708,format=(string) cc_data");
|
||||
static GstStaticCaps cea708_cdp_caps =
|
||||
GST_STATIC_CAPS ("closedcaption/x-cea-708,format=(string) cdp");
|
||||
|
||||
GST_START_TEST (no_captions)
|
||||
{
|
||||
|
@ -91,7 +89,6 @@ samples_selected_cb (GstAggregator * agg, GstSegment * segment,
|
|||
|
||||
buflist = gst_sample_get_buffer_list (captions_sample);
|
||||
fail_unless_equals_int (gst_buffer_list_length (buflist), 1);
|
||||
fail_unless (gst_buffer_list_get (buflist, 0) == expected_caption_buffer);
|
||||
gst_sample_unref (captions_sample);
|
||||
|
||||
gst_object_unref (caption_pad);
|
||||
|
@ -106,6 +103,7 @@ GST_START_TEST (captions_and_eos)
|
|||
GstCaps *caps;
|
||||
GstVideoCaptionMeta *meta;
|
||||
GstBuffer *second_video_buf, *second_caption_buf;
|
||||
const guint8 cc_data[3] = { 0x0, 0x0, 0x0 };
|
||||
|
||||
h = gst_harness_new_with_padnames ("cccombiner", "sink", "src");
|
||||
h2 = gst_harness_new_with_element (h->element, NULL, NULL);
|
||||
|
@ -127,7 +125,8 @@ GST_START_TEST (captions_and_eos)
|
|||
expected_video_buffer = buf;
|
||||
gst_harness_push (h, buf);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
buf = gst_buffer_new_and_alloc (3);
|
||||
gst_buffer_fill (buf, 0, cc_data, 3);
|
||||
GST_BUFFER_PTS (buf) = 0;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
expected_caption_buffer = buf;
|
||||
|
@ -141,7 +140,8 @@ GST_START_TEST (captions_and_eos)
|
|||
second_video_buf = buf;
|
||||
gst_harness_push (h, buf);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
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;
|
||||
second_caption_buf = buf;
|
||||
|
@ -158,7 +158,7 @@ GST_START_TEST (captions_and_eos)
|
|||
fail_unless (meta != NULL);
|
||||
fail_unless_equals_int (meta->caption_type,
|
||||
GST_VIDEO_CAPTION_TYPE_CEA708_RAW);
|
||||
fail_unless_equals_int (meta->size, 128);
|
||||
fail_unless_equals_int (meta->size, 3);
|
||||
|
||||
gst_buffer_unref (outbuf);
|
||||
|
||||
|
@ -174,91 +174,7 @@ GST_START_TEST (captions_and_eos)
|
|||
fail_unless (meta != NULL);
|
||||
fail_unless_equals_int (meta->caption_type,
|
||||
GST_VIDEO_CAPTION_TYPE_CEA708_RAW);
|
||||
fail_unless_equals_int (meta->size, 128);
|
||||
|
||||
gst_buffer_unref (outbuf);
|
||||
|
||||
/* Caps should be equal to input caps */
|
||||
caps = gst_pad_get_current_caps (h->sinkpad);
|
||||
fail_unless (caps != NULL);
|
||||
fail_unless (gst_caps_can_intersect (caps,
|
||||
gst_static_caps_get (&foo_bar_caps)));
|
||||
gst_caps_unref (caps);
|
||||
|
||||
gst_harness_teardown (h);
|
||||
gst_harness_teardown (h2);
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
GST_START_TEST (captions_type_change_and_eos)
|
||||
{
|
||||
GstHarness *h, *h2;
|
||||
GstBuffer *buf, *outbuf;
|
||||
GstPad *caption_pad;
|
||||
GstCaps *caps;
|
||||
GstVideoCaptionMeta *meta;
|
||||
|
||||
h = gst_harness_new_with_padnames ("cccombiner", "sink", "src");
|
||||
h2 = gst_harness_new_with_element (h->element, NULL, NULL);
|
||||
caption_pad = gst_element_get_request_pad (h->element, "caption");
|
||||
gst_harness_add_element_sink_pad (h2, caption_pad);
|
||||
gst_object_unref (caption_pad);
|
||||
|
||||
gst_harness_set_src_caps_str (h, foo_bar_caps.string);
|
||||
gst_harness_set_src_caps_str (h2, cea708_cc_data_caps.string);
|
||||
|
||||
/* Push a buffer and caption buffer */
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 0;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
gst_harness_push (h, buf);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 0;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
gst_harness_push (h2, buf);
|
||||
|
||||
/* Change caption type */
|
||||
gst_harness_set_src_caps_str (h2, cea708_cdp_caps.string);
|
||||
|
||||
/* And another one: the first video buffer should be retrievable
|
||||
* after the second caption buffer is pushed */
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
gst_harness_push (h, buf);
|
||||
|
||||
buf = gst_buffer_new_and_alloc (128);
|
||||
GST_BUFFER_PTS (buf) = 40 * GST_MSECOND;
|
||||
GST_BUFFER_DURATION (buf) = 40 * GST_MSECOND;
|
||||
gst_harness_push (h2, buf);
|
||||
|
||||
/* Pull the first output buffer */
|
||||
outbuf = gst_harness_pull (h);
|
||||
fail_unless (outbuf != NULL);
|
||||
|
||||
meta = gst_buffer_get_video_caption_meta (outbuf);
|
||||
fail_unless (meta != NULL);
|
||||
fail_unless_equals_int (meta->caption_type,
|
||||
GST_VIDEO_CAPTION_TYPE_CEA708_RAW);
|
||||
fail_unless_equals_int (meta->size, 128);
|
||||
|
||||
gst_buffer_unref (outbuf);
|
||||
|
||||
/* Push EOS on both pads get the second output buffer, we otherwise wait
|
||||
* in case there are further captions for the current video buffer */
|
||||
gst_harness_push_event (h, gst_event_new_eos ());
|
||||
gst_harness_push_event (h2, gst_event_new_eos ());
|
||||
|
||||
outbuf = gst_harness_pull (h);
|
||||
fail_unless (outbuf != NULL);
|
||||
|
||||
meta = gst_buffer_get_video_caption_meta (outbuf);
|
||||
fail_unless (meta != NULL);
|
||||
fail_unless_equals_int (meta->caption_type,
|
||||
GST_VIDEO_CAPTION_TYPE_CEA708_CDP);
|
||||
fail_unless_equals_int (meta->size, 128);
|
||||
fail_unless_equals_int (meta->size, 3);
|
||||
|
||||
gst_buffer_unref (outbuf);
|
||||
|
||||
|
@ -285,7 +201,6 @@ cccombiner_suite (void)
|
|||
|
||||
tcase_add_test (tc, no_captions);
|
||||
tcase_add_test (tc, captions_and_eos);
|
||||
tcase_add_test (tc, captions_type_change_and_eos);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue