diff --git a/src/gstreamer/gstlibcamerapad.cpp b/src/gstreamer/gstlibcamerapad.cpp
new file mode 100644
index 0000000..6212c3b
--- /dev/null
+++ b/src/gstreamer/gstlibcamerapad.cpp
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * gstlibcamerapad.cpp - GStreamer Capture Pad
+ */
+
+#include "gstlibcamerapad.h"
+#include "gstlibcamera-utils.h"
+
+#include <libcamera/stream.h>
+
+using namespace libcamera;
+
+struct _GstLibcameraPad {
+	GstPad parent;
+	StreamRole role;
+};
+
+enum {
+	PROP_0,
+	PROP_STREAM_ROLE
+};
+
+G_DEFINE_TYPE(GstLibcameraPad, gst_libcamera_pad, GST_TYPE_PAD);
+
+static void
+gst_libcamera_pad_set_property(GObject *object, guint prop_id,
+			       const GValue *value, GParamSpec *pspec)
+{
+	auto *self = GST_LIBCAMERA_PAD(object);
+	GLibLocker lock(GST_OBJECT(self));
+
+	switch (prop_id) {
+	case PROP_STREAM_ROLE:
+		self->role = (StreamRole)g_value_get_enum(value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gst_libcamera_pad_get_property(GObject *object, guint prop_id, GValue *value,
+			       GParamSpec *pspec)
+{
+	auto *self = GST_LIBCAMERA_PAD(object);
+	GLibLocker lock(GST_OBJECT(self));
+
+	switch (prop_id) {
+	case PROP_STREAM_ROLE:
+		g_value_set_enum(value, self->role);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gst_libcamera_pad_init(GstLibcameraPad *self)
+{
+}
+
+static GType
+gst_libcamera_stream_role_get_type(void)
+{
+	static GType type = 0;
+	static const GEnumValue values[] = {
+		{ StillCapture, "libcamera::StillCapture", "still-capture" },
+		{ VideoRecording, "libcamera::VideoRecording", "video-recording" },
+		{ Viewfinder, "libcamera::Viewfinder", "view-finder" },
+		{ 0, NULL, NULL }
+	};
+
+	if (!type)
+		type = g_enum_register_static("GstLibcameraStreamRole", values);
+
+	return type;
+}
+
+static void
+gst_libcamera_pad_class_init(GstLibcameraPadClass *klass)
+{
+	auto *object_class = G_OBJECT_CLASS(klass);
+
+	object_class->set_property = gst_libcamera_pad_set_property;
+	object_class->get_property = gst_libcamera_pad_get_property;
+
+	auto *spec = g_param_spec_enum("stream-role", "Stream Role",
+				       "The selected stream role",
+				       gst_libcamera_stream_role_get_type(),
+				       VideoRecording,
+				       (GParamFlags)(GST_PARAM_MUTABLE_READY
+					             | G_PARAM_CONSTRUCT
+						     | G_PARAM_READWRITE
+						     | G_PARAM_STATIC_STRINGS));
+	g_object_class_install_property(object_class, PROP_STREAM_ROLE, spec);
+}
diff --git a/src/gstreamer/gstlibcamerapad.h b/src/gstreamer/gstlibcamerapad.h
new file mode 100644
index 0000000..2e745f1
--- /dev/null
+++ b/src/gstreamer/gstlibcamerapad.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2019, Collabora Ltd.
+ *     Author: Nicolas Dufresne <nicolas.dufresne@collabora.com>
+ *
+ * gstlibcamerapad.h - GStreamer Capture Element
+ */
+
+#include <gst/gst.h>
+
+#ifndef __GST_LIBCAMERA_PAD_H__
+#define __GST_LIBCAMERA_PAD_H__
+
+#define GST_TYPE_LIBCAMERA_PAD gst_libcamera_pad_get_type()
+G_DECLARE_FINAL_TYPE(GstLibcameraPad, gst_libcamera_pad,
+		     GST_LIBCAMERA, PAD, GstPad)
+
+
+#endif /* __GST_LIBCAMERA_PAD_H__ */
diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp
index 3807503..085c489 100644
--- a/src/gstreamer/gstlibcamerasrc.cpp
+++ b/src/gstreamer/gstlibcamerasrc.cpp
@@ -6,6 +6,7 @@
  * gstlibcamerasrc.cpp - GStreamer Capture Element
  */
 
+#include "gstlibcamerapad.h"
 #include "gstlibcamerasrc.h"
 
 struct _GstLibcameraSrc {
@@ -14,6 +15,18 @@ struct _GstLibcameraSrc {
 
 G_DEFINE_TYPE(GstLibcameraSrc, gst_libcamera_src, GST_TYPE_ELEMENT);
 
+#define TEMPLATE_CAPS GST_STATIC_CAPS("video/x-raw; image/jpeg")
+
+/* For the simple case, we have a src pad that is always present. */
+GstStaticPadTemplate src_template = {
+	"src", GST_PAD_SRC, GST_PAD_ALWAYS, TEMPLATE_CAPS
+};
+
+/* More pads can be requested in state < PAUSED */
+GstStaticPadTemplate request_src_template = {
+	"src_%s", GST_PAD_SRC, GST_PAD_REQUEST, TEMPLATE_CAPS
+};
+
 static void
 gst_libcamera_src_init(GstLibcameraSrc *self)
 {
@@ -28,4 +41,10 @@ gst_libcamera_src_class_init(GstLibcameraSrcClass *klass)
 				       "libcamera Source", "Source/Video",
 				       "Linux Camera source using libcamera",
 				       "Nicolas Dufresne <nicolas.dufresne@collabora.com");
+	gst_element_class_add_static_pad_template_with_gtype(element_class,
+							     &src_template,
+							     GST_TYPE_LIBCAMERA_PAD);
+	gst_element_class_add_static_pad_template_with_gtype(element_class,
+							     &request_src_template,
+							     GST_TYPE_LIBCAMERA_PAD);
 }
diff --git a/src/gstreamer/meson.build b/src/gstreamer/meson.build
index a57dd85..1c4a2e3 100644
--- a/src/gstreamer/meson.build
+++ b/src/gstreamer/meson.build
@@ -1,6 +1,7 @@
 libcamera_gst_sources = [
     'gstlibcamera-utils.cpp',
     'gstlibcamera.c',
+    'gstlibcamerapad.cpp',
     'gstlibcameraprovider.cpp',
     'gstlibcamerasrc.cpp',
 ]
