/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2021, Vedant Paranjape
 *
 * gstreamer_multi_stream_test.cpp - GStreamer multi stream capture test
 */

#include <iostream>
#include <unistd.h>

#include <libcamera/libcamera.h>

#include <gst/gst.h>

#include "gstreamer_test.h"
#include "test.h"

#if !GST_CHECK_VERSION(1, 19, 1)
static inline GstPad *gst_element_request_pad_simple(GstElement *element,
						     const gchar *name)
{
	return gst_element_get_request_pad(element, name);
}
#endif

using namespace std;

class GstreamerMultiStreamTest : public GstreamerTest, public Test
{
public:
	GstreamerMultiStreamTest()
		: GstreamerTest()
	{
	}

protected:
	int init() override
	{
		if (status_ != TestPass)
			return status_;

		/* Check if platform supports multistream capture */
		libcamera::CameraManager cm;
		cm.start();
		bool cameraFound = false;
		for (auto &camera : cm.cameras()) {
			if (camera->streams().size() > 1) {
				cameraName_ = camera->id();
				cameraFound = true;
				cm.stop();
				break;
			}
		}

		if (!cameraFound) {
			cm.stop();
			return TestSkip;
		}

		const gchar *streamDescription = "queue ! fakesink";
		g_autoptr(GError) error = NULL;

		stream0_ = gst_parse_bin_from_description_full(streamDescription, TRUE,
							       NULL,
							       GST_PARSE_FLAG_FATAL_ERRORS,
							       &error);
		if (!stream0_) {
			g_printerr("Stream0 could not be created (%s)\n", error->message);
			return TestFail;
		}
		g_object_ref_sink(stream0_);

		stream1_ = gst_parse_bin_from_description_full(streamDescription, TRUE,
							       NULL,
							       GST_PARSE_FLAG_FATAL_ERRORS,
							       &error);
		if (!stream1_) {
			g_printerr("Stream1 could not be created (%s)\n", error->message);
			return TestFail;
		}
		g_object_ref_sink(stream1_);

		if (createPipeline() != TestPass)
			return TestFail;

		return TestPass;
	}

	int run() override
	{
		g_object_set(libcameraSrc_, "camera-name", cameraName_.c_str(), NULL);

		/* Build the pipeline */
		gst_bin_add_many(GST_BIN(pipeline_), libcameraSrc_,
				 stream0_, stream1_, NULL);

		g_autoptr(GstPad) src_pad = gst_element_get_static_pad(libcameraSrc_, "src");
		g_autoptr(GstPad) request_pad = gst_element_request_pad_simple(libcameraSrc_, "src_%u");

		{
			g_autoptr(GstPad) queue0_sink_pad = gst_element_get_static_pad(stream0_, "sink");
			g_autoptr(GstPad) queue1_sink_pad = gst_element_get_static_pad(stream1_, "sink");

			if (gst_pad_link(src_pad, queue0_sink_pad) != GST_PAD_LINK_OK ||
			    gst_pad_link(request_pad, queue1_sink_pad) != GST_PAD_LINK_OK) {
				g_printerr("Pads could not be linked.\n");
				return TestFail;
			}
		}

		if (startPipeline() != TestPass)
			return TestFail;

		if (processEvent() != TestPass)
			return TestFail;

		return TestPass;
	}

	void cleanup() override
	{
		g_clear_object(&stream0_);
		g_clear_object(&stream1_);
	}

private:
	std::string cameraName_;
	GstElement *stream0_;
	GstElement *stream1_;
};

TEST_REGISTER(GstreamerMultiStreamTest)