Although source element is paused or source video data is blocked, sink element keeps rendering and writing data to a file
I wonder why the autovideosink element keeps displaying and filesink element keeps writing the last input frame even though source element is paused and the video data is not flowing.
When the source element is paused, I think that sink element displaying or writing blank frame is correct behavior.
I tried to insert valve element which drops frame buffer between source element and sink element, but the result was the same.
An example source code which keeps displaying last input frame even though video source element is paused shown below.
For some additional context, this is running in a Windows 11 and Gstreamer version 1.22.4.
#include <gst/gst.h>
#include <cstdio>
enum class STATE
{
WAITING,
RECORDING,
PAUSING,
};
typedef struct _CustomData
{
GstElement* pipeline;
GstElement* src;
GstElement* rendersink;
GMainLoop* loop;
STATE state;
} CustomData;
static gboolean handle_keyboard(GIOChannel* source, GIOCondition cond, CustomData* data)
{
gchar* str = NULL;
GstBus* bus = NULL;
GstMessage* msg = NULL;
if (g_io_channel_read_line(source, &str, NULL, NULL,NULL) != G_IO_STATUS_NORMAL) {
return TRUE;
}
switch (g_ascii_tolower(str[0])) {
case 'p':
if (data->state == STATE::RECORDING)
{
g_print("Setting state to %s\n", "PAUSE");
data->state = STATE::PAUSING;
gst_element_set_state(data->src, GST_STATE_PAUSED);
}
else if (data->state == STATE::PAUSING)
{
g_print("Setting state to %s\n", "PLAYING");
data->state = STATE::RECORDING;
gst_element_set_state(data->src, GST_STATE_PLAYING);
}
break;
case 'q':
g_print("Finish\n");
g_main_loop_quit(data->loop);
break;
default:
break;
}
g_free(str);
return TRUE;
}
int main(int argc, char* argv[])
{
CustomData data;
GstStateChangeReturn ret;
gst_init(&argc, &argv);
data.pipeline = gst_pipeline_new("pipeline");
data.src = gst_element_factory_make("dshowvideosrc", "src");
data.rendersink = gst_element_factory_make("autovideosink", "autovideosink");
if (!data.pipeline || !data.src || !data.rendersink)
{
g_printerr("Failed to create elements\n");
return -1;
}
gst_bin_add_many(GST_BIN(data.pipeline), data.src, data.rendersink, NULL);
g_object_set(G_OBJECT(data.src), "device-index", 0, "do-timestamp", true, NULL);
if (!gst_element_link_filtered(data.src, data.rendersink, gst_caps_new_simple("video/x-raw",
"width", G_TYPE_INT, 1920,
"height", G_TYPE_INT, 1080,
"framerate", GST_TYPE_FRACTION, 30, 1,
NULL))) {
g_printerr("Failed to link src1 and comp\n");
gst_object_unref(data.pipeline);
return -1;
}
g_print("USAGE: Choose one of the following options, then press enter:\n"
" 'P' to toggle between PAUSE and PLAY\n"
" 'Q' to quit\n");
GIOChannel* io_stdin = g_io_channel_unix_new(_fileno(stdin));
g_io_add_watch(io_stdin, G_IO_IN, (GIOFunc)handle_keyboard, &data);
ret = gst_element_set_state(data.pipeline, GST_STATE_PLAYING);
data.state = STATE::RECORDING;
data.loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(data.loop);
gst_element_set_state(data.pipeline, GST_STATE_NULL);
gst_object_unref(data.pipeline);
return 0;
}