diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/QuickStreamer/item.cpp | 180 | ||||
-rw-r--r-- | src/QuickStreamer/item.h | 5 | ||||
-rw-r--r-- | src/QuickStreamer/plugin.cpp | 5 | ||||
-rw-r--r-- | src/examples/examples.pro | 2 | ||||
-rw-r--r-- | src/examples/piano/piano.cpp | 17 | ||||
-rw-r--r-- | src/examples/piano/piano.pro | 20 | ||||
-rw-r--r-- | src/examples/piano/piano.qrc | 8 | ||||
-rw-r--r-- | src/examples/piano/qml/DarkPianoKey.qml | 21 | ||||
-rw-r--r-- | src/examples/piano/qml/LightPianoKey.qml | 23 | ||||
-rw-r--r-- | src/examples/piano/qml/Piano.qml | 110 | ||||
-rw-r--r-- | src/examples/piano/qml/PianoKey.qml | 45 | ||||
-rw-r--r-- | src/src.pro | 6 | ||||
-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 |