Changing last element in a pipeline
This tutorial looks at the case of changing the middle element in the pipeline. But I cannot change the end element in the pipeline. Help me please.
#include <iostream>
#include <queue>
#include <string>
#include <boost/format.hpp>
#include <gst/gst.h>
#include "GStreamer/Utils.h"
GstPad* blockpad_1;
GstPad* blockpad_2;
GstElement* before_1;
GstElement* after_1;
GstElement* before_2;
GstElement* cur_effect;
GstElement* pipeline;
GstElement* sink_1;
GstElement* sink_2;
GstElement* q1;
GstElement* q2;
GstElement* q3;
std::queue<GstElement*> effects;
using namespace mongoose;
GstPadProbeReturn event_probe_cb_1(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) {
GMainLoop* loop = static_cast<GMainLoop*>(user_data);
GstElement* before = before_1;
GstElement* current = cur_effect;
GstElement* next = effects.front();
GstElement* after = after_1;
if (GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS) {
return GST_PAD_PROBE_PASS;
}
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
gst_object_ref(current);
effects.push(current);
effects.pop();
if (next == nullptr) {
g_main_loop_quit(loop);
return GST_PAD_PROBE_DROP;
}
auto msg = boost::format("Switching from '%s' to '%s'")
% GST_OBJECT_NAME(current)
% GST_OBJECT_NAME(next);
std::cout << msg << std::endl;
gst_element_set_state(current, GST_STATE_NULL);
gst_bin_remove(GST_BIN(pipeline), current);
gst_bin_add(GST_BIN(pipeline), next);
gst_element_link_many(before, next, after, NULL);
gst_element_set_state(next, GST_STATE_PLAYING);
cur_effect = next;
return GST_PAD_PROBE_DROP;
}
GstPadProbeReturn event_probe_cb_2(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) {
GMainLoop* loop = static_cast<GMainLoop*>(user_data);
GstElement* before = before_2;
GstElement* current = sink_1;
GstElement* next = sink_2;
if (GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS) {
return GST_PAD_PROBE_PASS;
}
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
gst_object_ref(current);
if (next == nullptr) {
g_main_loop_quit(loop);
return GST_PAD_PROBE_DROP;
}
auto msg = boost::format("Switching from '%s' to '%s'")
% GST_OBJECT_NAME(current)
% GST_OBJECT_NAME(next);
std::cout << msg << std::endl;
gst_element_set_state(current, GST_STATE_NULL);
gst_bin_remove(GST_BIN(pipeline), current);
gst_bin_add(GST_BIN(pipeline), next);
gst_element_link_many(before, next, NULL);
gst_element_set_state(next, GST_STATE_PLAYING);
return GST_PAD_PROBE_DROP;
}
GstPadProbeReturn pad_probe_cb_1(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) {
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
gst::Pad srcpad(gst_element_get_static_pad(cur_effect, "src"));
gst_pad_add_probe(
srcpad.get(),
GstPadProbeType(GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
event_probe_cb_1,
user_data,
NULL);
gst::Pad sinkpad(gst_element_get_static_pad(cur_effect, "sink"));
gst_pad_send_event(sinkpad.get(), gst_event_new_eos());
return GST_PAD_PROBE_OK;
}
GstPadProbeReturn pad_probe_cb_2(GstPad* pad, GstPadProbeInfo* info, gpointer user_data) {
gst_pad_remove_probe(pad, GST_PAD_PROBE_INFO_ID(info));
gst::Pad srcpad(gst_element_get_static_pad(sink_1, "sink"));
gst_pad_add_probe(
srcpad.get(),
GstPadProbeType(GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM),
event_probe_cb_2,
user_data,
NULL);
gst::Pad sinkpad(gst_element_get_static_pad(q3, "sink"));
gst_pad_send_event(sinkpad.get(), gst_event_new_eos());
return GST_PAD_PROBE_OK;
}
gboolean timeout_cb_1(gpointer user_data) {
gst_pad_add_probe(
blockpad_1,
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
pad_probe_cb_1,
user_data,
NULL);
return TRUE;
}
gboolean timeout_cb_2(gpointer user_data) {
gst_pad_add_probe(
blockpad_2,
GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
pad_probe_cb_2,
user_data,
NULL);
return FALSE;
}
gboolean bus_cb(GstBus* /*bus*/, GstMessage* msg, gpointer user_data) {
GMainLoop* loop = static_cast<GMainLoop*>(user_data);
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR: {
GError* err = NULL;
gchar* dbg;
gst_message_parse_error(msg, &err, &dbg);
gst_object_default_error(msg->src, err, dbg);
g_clear_error(&err);
g_free(dbg);
g_main_loop_quit(loop);
break;
}
default:
break;
}
return TRUE;
}
void work() {
std::vector<char const*> effect_names {
"identity",
"exclusion",
"navigationtest",
"agingtv",
"videoflip",
"vertigotv",
"gaussianblur",
"shagadelictv",
"edgetv"
};
gst_init(nullptr, nullptr);
for (auto const& e : effect_names) {
auto element = gst::create_element(e);
std::cout << "Effect: " << e << std::endl;
effects.push(element);
}
pipeline = gst::pipeline_new();
GstElement* src = gst::create_element("videotestsrc");
g_object_set(src, "is-live", TRUE, NULL);
GstElement* filter1 = gst::create_element("capsfilter");
gst_util_set_object_arg(
G_OBJECT(filter1),
"caps",
"video/x-raw, width=320, height=240, "
"format={ I420, YV12, YUY2, UYVY, AYUV, Y41B, Y42B, "
"YVYU, Y444, v210, v216, NV12, NV21, UYVP, A420, YUV9, YVU9, IYU1 }");
q1 = gst::create_element("queue");
q2 = gst::create_element("queue");
q3 = gst::create_element("queue");
blockpad_1 = gst_element_get_static_pad(q1, "src");
blockpad_2 = gst_element_get_static_pad(q3, "src");
before_1 = gst::create_element("videoconvert");
GstElement* effect = effects.front();
effects.pop();
cur_effect = effect;
after_1 = gst::create_element("videoconvert");
GstElement* filter2 = gst::create_element("capsfilter");
gst_util_set_object_arg(
G_OBJECT(filter2),
"caps",
"video/x-raw, width=320, height=240, "
"format={ RGBx, BGRx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR }");
GstElement* encoder = gst::create_element("x264enc");
GstElement* muxer = gst::create_element("mpegtsmux");
before_2 = q3;
//sink_1 = gst::create_element("autovideosink");
sink_1 = gst::create_element("filesink");
g_object_set(G_OBJECT(sink_1), "location", "/data/output_3.mp4", NULL);
sink_2 = gst::create_element("filesink");
g_object_set(G_OBJECT(sink_2), "location", "/data/output_4.mp4", NULL);
gst_bin_add_many(
GST_BIN(pipeline),
src,
filter1,
q1,
before_1,
effect,
after_1,
q2,
encoder,
muxer,
q3,
sink_1,
NULL);
gst_element_link_many(
src,
filter1,
q1,
before_1,
effect,
after_1,
q2,
encoder,
muxer,
q3,
sink_1,
NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gst_bus_add_watch(GST_ELEMENT_BUS(pipeline), bus_cb, loop);
//g_timeout_add_seconds(1, timeout_cb_1, loop);
g_timeout_add_seconds(3, timeout_cb_2, loop);
g_main_loop_run(loop);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
}
int main() {
try {
work();
} catch (std::exception const& e) {
std::cerr << e.what() << std::endl;
} catch (...) {
std::cerr << "Undefined exception!" << std::endl;
}
return 0;
}