mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-30 05:31:15 +00:00
videotestsrc: Don't re-render every frame when it's not needed.
When the pattern being rendered by videotestsrc doesn't have motion, cache a rendered buffer and output it repeatedly with updated metadata. Based on a patch by Edward Hervey <edward@centricular.com> Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/10 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1293>
This commit is contained in:
parent
b3c71584e0
commit
1b22ffdfbd
2 changed files with 142 additions and 21 deletions
|
@ -521,6 +521,59 @@ gst_video_test_src_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
|
||||||
return caps;
|
return caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_video_test_src_is_static_pattern (GstVideoTestSrc * videotestsrc)
|
||||||
|
{
|
||||||
|
switch (videotestsrc->pattern_type) {
|
||||||
|
case GST_VIDEO_TEST_SRC_SMPTE:
|
||||||
|
case GST_VIDEO_TEST_SRC_SNOW:
|
||||||
|
case GST_VIDEO_TEST_SRC_BLINK:
|
||||||
|
case GST_VIDEO_TEST_SRC_BALL:
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
case GST_VIDEO_TEST_SRC_ZONE_PLATE:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHROMA_ZONE_PLATE:
|
||||||
|
if (videotestsrc->kxt != 0 || videotestsrc->kyt != 0 ||
|
||||||
|
videotestsrc->kt != 0 || videotestsrc->kt2 != 0) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (videotestsrc->pattern_type) {
|
||||||
|
/* Any pattern that's not a solid color is non-static
|
||||||
|
* with horizontal motion */
|
||||||
|
case GST_VIDEO_TEST_SRC_SMPTE:
|
||||||
|
case GST_VIDEO_TEST_SRC_SNOW:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHECKERS1:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHECKERS2:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHECKERS4:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHECKERS8:
|
||||||
|
case GST_VIDEO_TEST_SRC_CIRCULAR:
|
||||||
|
case GST_VIDEO_TEST_SRC_BLINK:
|
||||||
|
case GST_VIDEO_TEST_SRC_SMPTE75:
|
||||||
|
case GST_VIDEO_TEST_SRC_ZONE_PLATE:
|
||||||
|
case GST_VIDEO_TEST_SRC_GAMUT:
|
||||||
|
case GST_VIDEO_TEST_SRC_CHROMA_ZONE_PLATE:
|
||||||
|
case GST_VIDEO_TEST_SRC_BALL:
|
||||||
|
case GST_VIDEO_TEST_SRC_SMPTE100:
|
||||||
|
case GST_VIDEO_TEST_SRC_BAR:
|
||||||
|
case GST_VIDEO_TEST_SRC_PINWHEEL:
|
||||||
|
case GST_VIDEO_TEST_SRC_SPOKES:
|
||||||
|
case GST_VIDEO_TEST_SRC_GRADIENT:
|
||||||
|
case GST_VIDEO_TEST_SRC_COLORS:
|
||||||
|
if (videotestsrc->horizontal_speed)
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_video_test_src_set_pattern (GstVideoTestSrc * videotestsrc,
|
gst_video_test_src_set_pattern (GstVideoTestSrc * videotestsrc,
|
||||||
int pattern_type)
|
int pattern_type)
|
||||||
|
@ -618,6 +671,7 @@ gst_video_test_src_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
{
|
{
|
||||||
GstVideoTestSrc *src = GST_VIDEO_TEST_SRC (object);
|
GstVideoTestSrc *src = GST_VIDEO_TEST_SRC (object);
|
||||||
|
gboolean invalidate = TRUE;
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_PATTERN:
|
case PROP_PATTERN:
|
||||||
|
@ -625,9 +679,11 @@ gst_video_test_src_set_property (GObject * object, guint prop_id,
|
||||||
break;
|
break;
|
||||||
case PROP_TIMESTAMP_OFFSET:
|
case PROP_TIMESTAMP_OFFSET:
|
||||||
src->timestamp_offset = g_value_get_int64 (value);
|
src->timestamp_offset = g_value_get_int64 (value);
|
||||||
|
invalidate = FALSE;
|
||||||
break;
|
break;
|
||||||
case PROP_IS_LIVE:
|
case PROP_IS_LIVE:
|
||||||
gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
|
gst_base_src_set_live (GST_BASE_SRC (src), g_value_get_boolean (value));
|
||||||
|
invalidate = FALSE;
|
||||||
break;
|
break;
|
||||||
case PROP_K0:
|
case PROP_K0:
|
||||||
src->k0 = g_value_get_int (value);
|
src->k0 = g_value_get_int (value);
|
||||||
|
@ -686,6 +742,12 @@ gst_video_test_src_set_property (GObject * object, guint prop_id,
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (invalidate) {
|
||||||
|
/* Property change invalidated the current pattern - check if it's static now or not */
|
||||||
|
src->have_static_pattern = gst_video_test_src_is_static_pattern (src);
|
||||||
|
gst_clear_buffer (&src->cached);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -964,6 +1026,8 @@ gst_video_test_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
|
||||||
videotestsrc->running_time = 0;
|
videotestsrc->running_time = 0;
|
||||||
videotestsrc->n_frames = 0;
|
videotestsrc->n_frames = 0;
|
||||||
|
|
||||||
|
gst_clear_buffer (&videotestsrc->cached);
|
||||||
|
|
||||||
GST_OBJECT_UNLOCK (videotestsrc);
|
GST_OBJECT_UNLOCK (videotestsrc);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -1132,10 +1196,9 @@ gst_video_test_src_is_seekable (GstBaseSrc * psrc)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_video_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
|
fill_image (GstPushSrc * psrc, GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
GstVideoTestSrc *src;
|
GstVideoTestSrc *src;
|
||||||
GstClockTime next_time;
|
|
||||||
GstVideoFrame frame;
|
GstVideoFrame frame;
|
||||||
gconstpointer pal;
|
gconstpointer pal;
|
||||||
gsize palsize;
|
gsize palsize;
|
||||||
|
@ -1155,18 +1218,9 @@ gst_video_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
|
||||||
goto eos;
|
goto eos;
|
||||||
}
|
}
|
||||||
|
|
||||||
GST_LOG_OBJECT (src,
|
|
||||||
"creating buffer from pool for frame %" G_GINT64_FORMAT, src->n_frames);
|
|
||||||
|
|
||||||
if (!gst_video_frame_map (&frame, &src->info, buffer, GST_MAP_WRITE))
|
if (!gst_video_frame_map (&frame, &src->info, buffer, GST_MAP_WRITE))
|
||||||
goto invalid_frame;
|
goto invalid_frame;
|
||||||
|
|
||||||
GST_BUFFER_PTS (buffer) =
|
|
||||||
src->accum_rtime + src->timestamp_offset + src->running_time;
|
|
||||||
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
|
|
||||||
|
|
||||||
gst_object_sync_values (GST_OBJECT (psrc), GST_BUFFER_PTS (buffer));
|
|
||||||
|
|
||||||
src->make_image (src, GST_BUFFER_PTS (buffer), &frame);
|
src->make_image (src, GST_BUFFER_PTS (buffer), &frame);
|
||||||
|
|
||||||
if ((pal = gst_video_format_get_palette (GST_VIDEO_FRAME_FORMAT (&frame),
|
if ((pal = gst_video_format_get_palette (GST_VIDEO_FRAME_FORMAT (&frame),
|
||||||
|
@ -1175,6 +1229,69 @@ gst_video_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_video_frame_unmap (&frame);
|
gst_video_frame_unmap (&frame);
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
|
not_negotiated:
|
||||||
|
{
|
||||||
|
return GST_FLOW_NOT_NEGOTIATED;
|
||||||
|
}
|
||||||
|
eos:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d", (gint) src->n_frames);
|
||||||
|
return GST_FLOW_EOS;
|
||||||
|
}
|
||||||
|
invalid_frame:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "invalid frame");
|
||||||
|
return GST_FLOW_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_video_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
|
||||||
|
{
|
||||||
|
GstVideoTestSrc *src = GST_VIDEO_TEST_SRC (psrc);
|
||||||
|
GstClockTime next_time;
|
||||||
|
GstFlowReturn ret;
|
||||||
|
|
||||||
|
GstClockTime pts =
|
||||||
|
src->accum_rtime + src->timestamp_offset + src->running_time;
|
||||||
|
|
||||||
|
gst_object_sync_values (GST_OBJECT (src), pts);
|
||||||
|
|
||||||
|
if (src->have_static_pattern) {
|
||||||
|
GstVideoFrame sframe, dframe;
|
||||||
|
|
||||||
|
if (src->cached == NULL) {
|
||||||
|
src->cached = gst_buffer_new_allocate (NULL, src->info.size, NULL);
|
||||||
|
|
||||||
|
ret = fill_image (GST_PUSH_SRC (src), src->cached);
|
||||||
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
|
goto fill_failed;
|
||||||
|
} else {
|
||||||
|
GST_LOG_OBJECT (src, "Reusing cached pattern buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do a memory copy instead of just passing a reference to this buffer to
|
||||||
|
* be consistent with other sources. This should make things clear for
|
||||||
|
* cases where downstream cannot queue the same buffer twice (such as v4l2)
|
||||||
|
*/
|
||||||
|
gst_video_frame_map (&sframe, &src->info, src->cached, GST_MAP_READ);
|
||||||
|
gst_video_frame_map (&dframe, &src->info, buffer, GST_MAP_WRITE);
|
||||||
|
|
||||||
|
if (!gst_video_frame_copy (&dframe, &sframe))
|
||||||
|
goto copy_failed;
|
||||||
|
|
||||||
|
gst_video_frame_unmap (&sframe);
|
||||||
|
gst_video_frame_unmap (&dframe);
|
||||||
|
} else {
|
||||||
|
ret = fill_image (GST_PUSH_SRC (src), buffer);
|
||||||
|
if (G_UNLIKELY (ret != GST_FLOW_OK))
|
||||||
|
goto fill_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_BUFFER_PTS (buffer) = pts;
|
||||||
|
GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "Timestamp: %" GST_TIME_FORMAT " = accumulated %"
|
GST_DEBUG_OBJECT (src, "Timestamp: %" GST_TIME_FORMAT " = accumulated %"
|
||||||
GST_TIME_FORMAT " + offset: %"
|
GST_TIME_FORMAT " + offset: %"
|
||||||
|
@ -1211,22 +1328,20 @@ gst_video_test_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
not_negotiated:
|
fill_failed:
|
||||||
{
|
{
|
||||||
return GST_FLOW_NOT_NEGOTIATED;
|
GST_DEBUG_OBJECT (src, "fill returned %d (%s)", ret,
|
||||||
|
gst_flow_get_name (ret));
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
eos:
|
copy_failed:
|
||||||
{
|
{
|
||||||
GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d", (gint) src->n_frames);
|
GST_DEBUG_OBJECT (src, "Failed to copy cached buffer");
|
||||||
return GST_FLOW_EOS;
|
return GST_FLOW_ERROR;
|
||||||
}
|
|
||||||
invalid_frame:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (src, "invalid frame");
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_video_test_src_start (GstBaseSrc * basesrc)
|
gst_video_test_src_start (GstBaseSrc * basesrc)
|
||||||
{
|
{
|
||||||
|
@ -1268,6 +1383,8 @@ gst_video_test_src_stop (GstBaseSrc * basesrc)
|
||||||
src->n_lines = 0;
|
src->n_lines = 0;
|
||||||
src->lines = NULL;
|
src->lines = NULL;
|
||||||
|
|
||||||
|
gst_clear_buffer (&src->cached);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,10 @@ struct _GstVideoTestSrc {
|
||||||
guint n_lines;
|
guint n_lines;
|
||||||
gint offset;
|
gint offset;
|
||||||
gpointer *lines;
|
gpointer *lines;
|
||||||
|
|
||||||
|
/* cached buffer used for static patterns that don't change */
|
||||||
|
GstBuffer *cached;
|
||||||
|
gboolean have_static_pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_ELEMENT_REGISTER_DECLARE (videotestsrc);
|
GST_ELEMENT_REGISTER_DECLARE (videotestsrc);
|
||||||
|
|
Loading…
Reference in a new issue