Ok, I have been struggling for a few days now.
I believe it must/can work but I am missing something.
So I would like to approach it step by step and hope someone can help me with these little steps.
So,
I have my application code simplified for this question.
I have a pipeline with two bins that contain filesrc, decodebin, videoconvert.
I add the bins to a compositor to overlay the video outputs.
I want to loop video 1 when the EOS signal has been received.
So I do not want to see video 2 again, this happens when I seek the entire pipeline.
How can I individually loop video 1 when they are both connected to the compositor in the pipeline?
#include <gst/gst.h>
#include <iostream>
typedef struct {
GstElement *pipeline = nullptr;
GstElement *compositor = nullptr;
GstElement *videoConvert = nullptr;
GstElement *sinkVideo = nullptr;
} s_base;
typedef struct {
GstElement *bin = nullptr;
GstElement *source = nullptr;
GstElement *decode = nullptr;
GstElement *videoConvert = nullptr;
gint xpos = 0;
gint ypos = 0;
guint zorder = 0;
} s_video;
static void pad_added_handler(GstElement *src, GstPad *pad, gpointer data) {
GstElement *videoconvert = static_cast<GstElement *>(data);
GstPad *sinkPad = gst_element_get_static_pad(videoconvert, "sink");
if (!gst_pad_is_linked(sinkPad)) {
gst_pad_link(pad, sinkPad);
}
gst_object_unref(sinkPad);
}
s_video create_video_element(const std::string &filePath, gint xpos, gint ypos, guint zorder) {
s_video ve;
ve.bin = gst_bin_new(nullptr);
ve.source = gst_element_factory_make("filesrc", nullptr);
g_object_set(ve.source, "location", filePath.c_str(), nullptr);
ve.decode = gst_element_factory_make("decodebin", nullptr);
ve.videoConvert = gst_element_factory_make("videoconvert", nullptr);
ve.xpos = xpos;
ve.ypos = ypos;
ve.zorder = zorder;
gst_bin_add_many(GST_BIN(ve.bin), ve.source, ve.decode, ve.videoConvert, nullptr);
gst_element_link(ve.source, ve.decode);
gst_element_link(ve.videoConvert, nullptr);
g_signal_connect(ve.decode, "pad-added", G_CALLBACK(pad_added_handler), ve.videoConvert);
GstPad *ghostPad = gst_ghost_pad_new("src", gst_element_get_static_pad(ve.videoConvert, "src"));
gst_element_add_pad(ve.bin, ghostPad);
return ve;
}
static void bus_message_handler(GstBus *bus, GstMessage *msg, gpointer user_data) {
GstElement *element = static_cast<GstElement *>(user_data);
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS) {
gboolean res = gst_element_seek(
element,
1.0,
GST_FORMAT_TIME,
(GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
GST_SEEK_TYPE_SET,
0,
GST_SEEK_TYPE_NONE,
GST_CLOCK_TIME_NONE
);
if (!res) {
std::cerr << "Loop seek video1 failed!" << std::endl;
}
}
}
int main(int argc, char *argv[]) {
gst_init(&argc, &argv);
gtk_init(&argc, &argv);
gst_pb_utils_init();
s_base base;
base.pipeline = gst_pipeline_new("main-pipeline");
base.compositor = gst_element_factory_make("compositor", "compositor");
base.videoConvert = gst_element_factory_make("videoconvert", "videoConvert");
base.sinkVideo = gst_element_factory_make("autovideosink", "sinkVideo");
gst_bin_add_many(GST_BIN(base.pipeline), base.compositor, base.videoConvert, base.sinkVideo, nullptr);
gst_element_link_many(base.compositor, base.videoConvert, base.sinkVideo, nullptr);
s_video video1 = create_video_element("video1", 0, 0, 0);
s_video video2 = create_video_element("video2", 320, 0, 1);
gst_bin_add(GST_BIN(base.pipeline), video1.bin);
gst_bin_add(GST_BIN(base.pipeline), video2.bin);
auto link_to_compositor = [](s_video &ve, GstElement *compositor) {
GstPadTemplate *templ = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(compositor), "sink_%u");
GstPad *compSinkPad = gst_element_request_pad(compositor, templ, nullptr, nullptr);
g_object_set(compSinkPad, "xpos", ve.xpos, "ypos", ve.ypos, "zorder", ve.zorder, nullptr);
GstPad *srcPad = gst_element_get_static_pad(ve.bin, "src");
gst_pad_link(srcPad, compSinkPad);
gst_object_unref(srcPad);
gst_object_unref(compSinkPad);
};
link_to_compositor(video1, base.compositor);
link_to_compositor(video2, base.compositor);
GstBus *bus = gst_element_get_bus(base.pipeline);
gst_bus_add_signal_watch(bus);
g_signal_connect(bus, "message", G_CALLBACK(bus_message_handler), video1.bin);
gst_object_unref(bus);
gst_element_set_state(base.pipeline, GST_STATE_PLAYING);
GMainLoop *loop = g_main_loop_new(nullptr, FALSE);
g_main_loop_run(loop);
gst_element_set_state(base.pipeline, GST_STATE_NULL);
gst_object_unref(base.pipeline);
return 0;
}
Looking forward to some reaction!