summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/QuickStreamer/item.cpp180
-rw-r--r--src/QuickStreamer/item.h5
-rw-r--r--src/QuickStreamer/plugin.cpp5
-rw-r--r--src/examples/examples.pro2
-rw-r--r--src/examples/piano/piano.cpp17
-rw-r--r--src/examples/piano/piano.pro20
-rw-r--r--src/examples/piano/piano.qrc8
-rw-r--r--src/examples/piano/qml/DarkPianoKey.qml21
-rw-r--r--src/examples/piano/qml/LightPianoKey.qml23
-rw-r--r--src/examples/piano/qml/Piano.qml110
-rw-r--r--src/examples/piano/qml/PianoKey.qml45
-rw-r--r--src/src.pro6
-rw-r--r--src/tools/makeitempads.cpp (renamed from src/Tools/makeitempads.cpp)0
-rw-r--r--src/tools/makeitempads.pro (renamed from src/Tools/makeitempads.pro)0
-rw-r--r--src/tools/tools.pro (renamed from src/Tools/Tools.pro)0
15 files changed, 411 insertions, 31 deletions
diff --git a/src/QuickStreamer/item.cpp b/src/QuickStreamer/item.cpp
index 7539d07..90d06bb 100644
--- a/src/QuickStreamer/item.cpp
+++ b/src/QuickStreamer/item.cpp
@@ -12,10 +12,13 @@
namespace QQuickStreamer {
namespace Private {
+typedef QQmlListProperty<QObject> ItemList;
+// FIXME typedef QQmlListProperty<Item> ItemList;
+
struct PropertyInfo
{
- typedef std::function<void(GstObject *target, void *value)> ReadDelegate;
- typedef std::function<void(GstObject *target, const void *value)> WriteDelegate;
+ typedef std::function<void(Item *item, void *value)> ReadDelegate;
+ typedef std::function<void(Item *item, const void *value)> WriteDelegate;
const char *name;
ReadDelegate read;
@@ -249,36 +252,85 @@ static void writeValue(const void *input, GValue *output)
}
}
-static void readGObjectProperty(GstObject *target, const QByteArray &propertyName,
- GType propertyType, void *value)
+static void readGObjectProperty(Item *item, const QByteArray &name, GType type, void *value)
{
GValue gvalue = G_VALUE_INIT;
- g_value_init(&gvalue, propertyType);
- g_object_get_property(G_OBJECT(target), propertyName.constData(), &gvalue);
+ g_value_init(&gvalue, type);
+ g_object_get_property(G_OBJECT(item->target()), name.constData(), &gvalue);
readValue(&gvalue, value);
g_value_unset(&gvalue);
}
-static void writeGObjectProperty(GstObject *target, const QByteArray &propertyName,
- GType propertyType, const void *value)
+static void writeGObjectProperty(Item *item, const QByteArray &name, GType type, const void *value)
{
GValue gvalue = G_VALUE_INIT;
- g_value_init(&gvalue, propertyType);
+ g_value_init(&gvalue, type);
writeValue(value, &gvalue);
- g_object_set_property(G_OBJECT(target), propertyName.constData(), &gvalue);
+ g_object_set_property(G_OBJECT(item->target()), name.constData(), &gvalue);
g_value_unset(&gvalue);
}
-static void readNothing(GstObject *target, const QByteArray &name, void *)
+static void readNothing(Item *item, const QByteArray &name, void *)
{
qWarning("Cannot read \"%s::%s\" which is not declared readable",
- G_OBJECT_TYPE_NAME(target), name.constData());
+ G_OBJECT_TYPE_NAME(item->target()), name.constData());
}
-static void writeNothing(GstObject *target, const QByteArray &name, const void *)
+static void writeNothing(Item *item, const QByteArray &name, const void *)
{
qWarning("Cannot write \"%s::%s\" which is not declared writable",
- G_OBJECT_TYPE_NAME(target), name.constData());
+ G_OBJECT_TYPE_NAME(item->target()), name.constData());
+}
+
+static void appendChild(ItemList *list, QObject *child)
+{
+ auto *const parentItem = static_cast<Item *>(list->object);
+ auto *const childItem = static_cast<Item *>(child);
+
+ gst_bin_add(GST_BIN(parentItem->target()),
+ GST_ELEMENT(childItem->target()));
+}
+
+static int countChildren(ItemList *list)
+{
+ auto *const parentItem = static_cast<Item *>(list->object);
+ return GST_BIN_NUMCHILDREN(parentItem->target());
+}
+
+static QObject *childAt(ItemList *list, int offset)
+{
+ // FIXME: need to store the wrapper object somewhere
+ qDebug() << Q_FUNC_INFO;
+}
+
+static void clearChildren(ItemList *list)
+{
+ auto *const parentItem = static_cast<Item *>(list->object);
+ auto *const elementBin = GST_BIN(parentItem->target());
+
+ while (elementBin->children)
+ gst_bin_remove(elementBin, GST_ELEMENT(elementBin->children->data));
+}
+
+static void readChildren(Item *item, void *value)
+{
+ *static_cast<ItemList *>(value) =
+ ItemList(item, Q_NULLPTR, &appendChild, &countChildren, &childAt, &clearChildren);
+}
+
+static void readState(Item *item, void *value)
+{
+ // FIXME: check return value, cache last value?
+ gst_element_get_state(GST_ELEMENT(item->target()),
+ static_cast<GstState *>(value),
+ Q_NULLPTR, GST_CLOCK_TIME_NONE); // FIXME: infinite timeout?
+}
+
+static void writeState(Item *item, const void *value)
+{
+ const auto success = gst_element_set_state(GST_ELEMENT(item->target()),
+ *static_cast<const GstState *>(value));
+ qDebug("setState: %d", success);
}
template<typename... Args>
@@ -301,6 +353,14 @@ struct TypeInfo
{
}
+ static QMetaObject *createItemMetaObject()
+ {
+ QMetaObjectBuilder objectBuilder;
+ objectBuilder.setClassName(QByteArrayLiteral("QQuickStreamer::Item"));
+ objectBuilder.setSuperClass(&QObject::staticMetaObject);
+ return objectBuilder.toMetaObject();
+ }
+
static const TypeInfo *create(GType type, const MetaTypePads &metaTypePads)
{
QScopedPointer<TypeInfo> typeInfo(new TypeInfo);
@@ -311,8 +371,38 @@ struct TypeInfo
if (type != G_TYPE_OBJECT)
typeInfo->parent = find(g_type_parent(type));
+// FIXME static QMetaObject *const itemMetaObject = createItemMetaObject();
objectBuilder.setSuperClass(typeInfo->parent ? typeInfo->parent->metaObject
: &QObject::staticMetaObject);
+// FIXME : itemMetaObject);
+
+ if (g_type_is_a(type, GST_TYPE_BIN)) {
+ auto notifier = objectBuilder.addSignal(QByteArrayLiteral("childrenChanged()"));
+ auto property = objectBuilder.addProperty(QByteArrayLiteral("children"),
+ QByteArrayLiteral("QQmlListProperty<QObject>"),
+// FIXME QByteArrayLiteral("QQmlListProperty<QQuickStreamer::Item>"),
+ notifier.index());
+
+ property.setReadable(true);
+ property.setWritable(false);
+
+ typeInfo->properties.append({Q_NULLPTR, readChildren, Q_NULLPTR});
+ objectBuilder.addClassInfo(QByteArrayLiteral("DefaultProperty"), property.name());
+ }
+
+ if (g_type_is_a(type, GST_TYPE_ELEMENT)) {
+ // FIXME: also add pendingState property?
+
+ auto notifier = objectBuilder.addSignal(QByteArrayLiteral("stateChanged()"));
+ auto property = objectBuilder.addProperty(QByteArrayLiteral("state"),
+ QByteArrayLiteral("int"), // FIXME
+ notifier.index());
+
+ property.setReadable(true);
+ property.setWritable(true);
+
+ typeInfo->properties.append({Q_NULLPTR, readState, writeState});
+ }
const auto gobject_class = static_cast<GObjectClass *>(g_type_class_ref(type));
@@ -391,14 +481,15 @@ struct TypeInfo
const static int MAJOR_VERSION = 1;
const static int MINOR_VERSION = 0;
- auto pointerName = objectBuilder.className() + QByteArrayLiteral(" *");
+ auto listName = QByteArrayLiteral("QQmlListProperty<") + objectBuilder.className() + '>';
QQmlPrivate::RegisterType qmlType = {
1,
typeId,
- 0 /*qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData())*/,
- sizeof(Item), metaTypePads.createInto,
+ 0, // FIXME: qRegisterNormalizedMetaType<ItemList>(listName.constData()),
+ sizeof(Item),
+ metaTypePads.createInto,
QString(),
NAMESPACE_URI, MAJOR_VERSION, MINOR_VERSION,
@@ -450,28 +541,28 @@ struct TypeInfo
return typeInfo;
}
- int readProperty(GstObject *object, int id, QVariant *value) const
+ int readProperty(Item *item, int id, QVariant *value) const
{
if (parent)
- id = parent->readProperty(object, id, value);
+ id = parent->readProperty(item, id, value);
if (id < 0)
return id;
if (id < properties.size())
- properties.at(id).read(object, value);
+ properties.at(id).read(item, value);
return id - properties.size();
}
- int writeProperty(GstObject *object, int id, const void *value) const
+ int writeProperty(Item *item, int id, const void *value) const
{
if (parent)
- id = parent->writeProperty(object, id, value);
+ id = parent->writeProperty(item, id, value);
if (id < 0)
return id;
if (id < properties.size())
- properties.at(id).write(object, value);
+ properties.at(id).write(item, value);
return id - properties.size();
}
@@ -512,7 +603,9 @@ Item::Item(GstObject *target, QObject *parent)
Q_ASSERT(m_target != Q_NULLPTR);
g_object_ref_sink(m_target);
- g_signal_connect_swapped(target, "notify", reinterpret_cast<GCallback>(&Item::emitPropertyChanged), this);
+
+ auto notifyCallback = reinterpret_cast<GCallback>(&Item::emitPropertyChanged);
+ g_signal_connect_swapped(target, "notify", notifyCallback, this);
}
Item::Item(const Item &other)
@@ -592,26 +685,55 @@ int Item::qt_metacall(QMetaObject::Call call, int id, void **args)
void Item::classBegin()
{
- Q_ASSERT(parent() != Q_NULLPTR);
- qDebug() << Q_FUNC_INFO << metaObject()->className() << parent()->children();
+ // nothing to do right now
}
void Item::componentComplete()
{
Q_ASSERT(parent() != Q_NULLPTR);
- qDebug() << Q_FUNC_INFO << metaObject()->className() << parent()->children();
+
+ qDebug()
+ << Q_FUNC_INFO
+ << gst_element_get_bus(GST_ELEMENT(m_target))
+ << gst_object_get_parent(m_target);
+
+ if (GST_IS_BIN(m_target)) {
+ auto l = g_list_last(GST_BIN_CHILDREN(m_target));
+
+ if (l) {
+ while (l->prev) {
+ bool linking_failed = true;
+
+ while (gst_element_link(GST_ELEMENT(l->data), GST_ELEMENT(l->prev->data)))
+ linking_failed = false;
+
+ if (linking_failed) {
+ qWarning("Could not link \"%s\" with \"%s\"",
+ gst_element_get_name(GST_ELEMENT(l->data)),
+ gst_element_get_name(GST_ELEMENT(l->prev->data)));
+ }
+
+ l = l->prev;
+ }
+ }
+ }
+}
+
+GstObject *Item::target() const
+{
+ return m_target;
}
int Item::readProperty(int id, QVariant *value)
{
const auto *const typeInfo = TypeInfo::find(G_OBJECT_TYPE(m_target));
- return typeInfo->readProperty(m_target, id, value);
+ return typeInfo->readProperty(this, id, value);
}
int Item::writeProperty(int id, const void *value)
{
const auto *const typeInfo = TypeInfo::find(G_OBJECT_TYPE(m_target));
- return typeInfo->writeProperty(m_target, id, value);
+ return typeInfo->writeProperty(this, id, value);
}
void Item::emitPropertyChanged(Item *self, GParamSpec *pspec)
diff --git a/src/QuickStreamer/item.h b/src/QuickStreamer/item.h
index beff427..bc0bf24 100644
--- a/src/QuickStreamer/item.h
+++ b/src/QuickStreamer/item.h
@@ -2,6 +2,7 @@
#define QQUICKSTREAMER_ITEM_H
#include <QObject>
+#include <QQmlListProperty>
#include <QQmlParserStatus>
typedef unsigned long GType;
@@ -33,6 +34,8 @@ public:
void classBegin() Q_DECL_OVERRIDE;
void componentComplete() Q_DECL_OVERRIDE;
+ GstObject *target() const;
+
protected:
int readProperty(int id, QVariant *value);
int writeProperty(int id, const void *value);
@@ -44,4 +47,6 @@ private:
} // namespace QQuickStreamer
+Q_DECLARE_METATYPE(QQmlListProperty<QQuickStreamer::Item>)
+
#endif // QQUICKSTREAMER_ITEM_H
diff --git a/src/QuickStreamer/plugin.cpp b/src/QuickStreamer/plugin.cpp
index be65cbe..fd10f2f 100644
--- a/src/QuickStreamer/plugin.cpp
+++ b/src/QuickStreamer/plugin.cpp
@@ -3,6 +3,8 @@
#include <gst/gst.h>
+#include <QtQml>
+
namespace QQuickStreamer {
static const auto NAMESPACE_URI = QByteArrayLiteral("QuickStreamer");
@@ -26,6 +28,9 @@ void Plugin::registerTypes(const char *uri)
}
}
+ Item::registerObjectClass(GST_TYPE_BIN);
+ Item::registerObjectClass(GST_TYPE_PIPELINE);
+
auto *const elements = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ANY, GST_RANK_NONE);
for (auto *l = elements; l; l = l->next) {
diff --git a/src/examples/examples.pro b/src/examples/examples.pro
new file mode 100644
index 0000000..5220e0f
--- /dev/null
+++ b/src/examples/examples.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS = piano
diff --git a/src/examples/piano/piano.cpp b/src/examples/piano/piano.cpp
new file mode 100644
index 0000000..55e0bde
--- /dev/null
+++ b/src/examples/piano/piano.cpp
@@ -0,0 +1,17 @@
+#include <QGuiApplication>
+#include <QQmlEngine>
+#include <QQuickView>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ app.setApplicationName("The QuickStreamer Piano");
+
+ QQuickView view;
+ view.engine()->addImportPath(TOP_OUTDIR "/src");
+ view.setSource(QUrl("qrc:///qml/Piano.qml"));
+ QObject::connect(&view, SIGNAL(destroyed()), &app, SLOT(quit()));
+ view.show();
+
+ return app.exec();
+}
diff --git a/src/examples/piano/piano.pro b/src/examples/piano/piano.pro
new file mode 100644
index 0000000..fbf020a
--- /dev/null
+++ b/src/examples/piano/piano.pro
@@ -0,0 +1,20 @@
+TEMPLATE = app
+QT = quick
+
+DEFINES += \
+ TOP_OUTDIR=\\\"$$TOP_OUTDIR/\\\" \
+ TOP_SRCDIR=\\\"$$TOP_SRCDIR/\\\" \
+ OUTDIR=\\\"$$OUT_PWD/\\\" \
+ SRCDIR=\\\"$$PWD/\\\"
+
+SOURCES += \
+ piano.cpp
+
+RESOURCES += \
+ piano.qrc
+
+OTHER_FILES += \
+ qml/Piano.qml \
+ qml/PianoKey.qml \
+ qml/DarkPianoKey.qml \
+ qml/LightPianoKey.qml
diff --git a/src/examples/piano/piano.qrc b/src/examples/piano/piano.qrc
new file mode 100644
index 0000000..32a90b7
--- /dev/null
+++ b/src/examples/piano/piano.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/Piano.qml</file>
+ <file>qml/PianoKey.qml</file>
+ <file>qml/DarkPianoKey.qml</file>
+ <file>qml/LightPianoKey.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/examples/piano/qml/DarkPianoKey.qml b/src/examples/piano/qml/DarkPianoKey.qml
new file mode 100644
index 0000000..23ed556
--- /dev/null
+++ b/src/examples/piano/qml/DarkPianoKey.qml
@@ -0,0 +1,21 @@
+import QtQuick 2.0
+
+PianoKey {
+ Gradient {
+ id: releasedGradient
+ GradientStop { position: 0.00; color: "#000" }
+ GradientStop { position: 0.90; color: "#333" }
+ GradientStop { position: 0.93; color: "#fff" }
+ GradientStop { position: 0.95; color: "#222" }
+ GradientStop { position: 1.00; color: "#000" }
+ }
+
+ Gradient {
+ id: pressedGradient
+ GradientStop { position: 0.00; color: "#000" }
+ GradientStop { position: 0.95; color: "#333" }
+ GradientStop { position: 1.00; color: "#fff" }
+ }
+
+ gradient: pressed ? pressedGradient : releasedGradient
+}
diff --git a/src/examples/piano/qml/LightPianoKey.qml b/src/examples/piano/qml/LightPianoKey.qml
new file mode 100644
index 0000000..5078052
--- /dev/null
+++ b/src/examples/piano/qml/LightPianoKey.qml
@@ -0,0 +1,23 @@
+import QtQuick 2.0
+
+PianoKey {
+ Gradient {
+ id: releasedGradient
+ GradientStop { position: 0.00; color: "#ccc" }
+ GradientStop { position: 0.10; color: "#eee" }
+ GradientStop { position: 0.30; color: "#fff" }
+ GradientStop { position: 0.95; color: "#fff" }
+ GradientStop { position: 1.00; color: "#ddd" }
+ }
+
+ Gradient {
+ id: pressedGradient
+ GradientStop { position: 0.00; color: "#ccc" }
+ GradientStop { position: 0.10; color: "#eee" }
+ GradientStop { position: 0.30; color: "#fff" }
+ GradientStop { position: 0.50; color: "#fff" }
+ GradientStop { position: 1.00; color: "#ddd" }
+ }
+
+ gradient: pressed ? pressedGradient : releasedGradient
+}
diff --git a/src/examples/piano/qml/Piano.qml b/src/examples/piano/qml/Piano.qml
new file mode 100644
index 0000000..d0a8711
--- /dev/null
+++ b/src/examples/piano/qml/Piano.qml
@@ -0,0 +1,110 @@
+import QtQuick 2.0
+import QuickStreamer 1.0
+
+Rectangle {
+ width: 800
+ height: 600
+ color: "#284"
+
+ Row {
+ id: lightKeys
+ anchors.centerIn: parent
+
+ Repeater {
+ model: 28
+
+ LightPianoKey {
+ width: 24
+ height: 145
+
+ note: {
+ var n = "cdefgah"[index % 7]
+
+ if (index < 7)
+ return n.toUpperCase();
+
+ return n + "'''".substr(4 - Math.floor(index / 7))
+ }
+
+ frequency: {
+ return 220 * Math.pow(Math.pow(2, 1/12),
+ Math.floor(index / 7) * 12 +
+ [0, 2, 4, 5, 7, 9, 11][index % 7])
+ }
+
+ onPressedChanged: {
+ audioSource.freq = frequency
+ audioSource.volume = pressed ? 1 : 0
+ pipeline.state = 4
+ }
+ }
+ }
+ }
+
+ Row {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: lightKeys.top
+ }
+
+ spacing: 11
+
+ Repeater {
+ model: 27
+
+ Item {
+ width: 13
+ height: 100
+
+ DarkPianoKey {
+ anchors.fill: parent
+ visible: (index % 7) != 2 && (index % 7) != 6
+
+ frequency: {
+ return 220 * Math.pow(Math.pow(2, 1/12),
+ Math.floor(index / 7) * 12 +
+ [1, 3, 0, 6, 8, 10, 0][index % 7])
+ }
+
+ onPressedChanged: {
+ audioSource.freq = frequency
+ audioSource.volume = pressed ? 1 : 0
+ pipeline.state = 4
+ }
+ }
+ }
+ }
+ }
+
+ Pipeline {
+ id: pipeline
+// state: 4 // FIXME: this should be an enum
+
+ AudioTestSrc {
+ id: audioSource
+
+ Behavior on volume {
+ NumberAnimation {
+ easing: Easing.OutQuart
+ duration: 100
+ }
+ }
+
+ /* fun:
+ Behavior on freq {
+ NumberAnimation {
+ easing: Easing.OutQuart
+ duration: 1500
+ }
+ }
+ */
+
+ volume: 0
+// wave: 12
+ }
+
+ AutoAudioSink {
+ id: audioSink
+ }
+ }
+}
diff --git a/src/examples/piano/qml/PianoKey.qml b/src/examples/piano/qml/PianoKey.qml
new file mode 100644
index 0000000..a695557
--- /dev/null
+++ b/src/examples/piano/qml/PianoKey.qml
@@ -0,0 +1,45 @@
+import QtQuick 2.0
+
+Rectangle {
+ property bool pressed: false
+ property double frequency: 440
+ property string note: ""
+
+ border {
+ color: "#000"
+ width: 1
+ }
+
+ width: 25
+ height: 100
+
+ MouseArea {
+ anchors { fill:parent; margins: 1 }
+ onReleased: parent.pressed = false
+ onPressed: parent.pressed = true
+ }
+
+ Text {
+ anchors {
+ top: parent.bottom
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ text: note
+ visible: note
+ opacity: parent.pressed ? 1 : 0.8
+ font.bold: parent.pressed
+ }
+
+ Text {
+ anchors {
+ bottom: parent.top
+ bottomMargin: 50
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ text: parent.frequency
+ font.pixelSize: 8
+ rotation: 90
+ }
+}
diff --git a/src/src.pro b/src/src.pro
index 28f8436..dd0fbac 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,7 +1,9 @@
TEMPLATE = subdirs
SUBDIRS = \
+ examples \
QuickStreamer \
- Tools
+ tools
-QuickStreamer.depends = Tools
+examples.depends = QuickStreamer
+QuickStreamer.depends = tools
diff --git a/src/Tools/makeitempads.cpp b/src/tools/makeitempads.cpp
index 5701ab3..5701ab3 100644
--- a/src/Tools/makeitempads.cpp
+++ b/src/tools/makeitempads.cpp
diff --git a/src/Tools/makeitempads.pro b/src/tools/makeitempads.pro
index 642ffe3..642ffe3 100644
--- a/src/Tools/makeitempads.pro
+++ b/src/tools/makeitempads.pro
diff --git a/src/Tools/Tools.pro b/src/tools/tools.pro
index d41f4c6..d41f4c6 100644
--- a/src/Tools/Tools.pro
+++ b/src/tools/tools.pro