Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • gstreamer gstreamer
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 670
    • Issues 670
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 353
    • Merge requests 353
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Monitor
    • Monitor
    • Incidents
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • GStreamer
  • gstreamergstreamer
  • Issues
  • #675

Closed
Open
Created Mar 24, 2021 by Maxim Maxim@Maxim

Changing last element in a pipeline

GStreamer Doc

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;
}
Edited Mar 24, 2021 by Maxim Maxim
Assignee
Assign to
Time tracking