mirror of
https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio.git
synced 2024-11-14 12:51:13 +00:00
initial commit
This commit is contained in:
parent
0dae1e94e4
commit
5e14d4bda4
24 changed files with 3454 additions and 0 deletions
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
Makefile*
|
||||
debug/*
|
||||
object_script*
|
||||
pipeviz_plugin_import.cpp
|
||||
pipeviz
|
||||
*.o
|
||||
moc_*
|
||||
src/version_info.h
|
42
pipeviz.pro
Normal file
42
pipeviz.pro
Normal file
|
@ -0,0 +1,42 @@
|
|||
######################################################################
|
||||
# Automatically generated by qmake (3.0) ?? ???. 22 21:50:14 2014
|
||||
######################################################################
|
||||
|
||||
CONFIG += qt debug
|
||||
TEMPLATE = app
|
||||
TARGET = pipeviz
|
||||
QT += widgets
|
||||
QT += xml
|
||||
QT += core
|
||||
INCLUDEPATH += . src
|
||||
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += gstreamer-1.0
|
||||
|
||||
gitinfo.commands = src/verinfo/verinfo.sh src/version src/version_info.h
|
||||
gitinfo.target = gitinfo
|
||||
|
||||
QMAKE_EXTRA_TARGETS += gitinfo
|
||||
|
||||
|
||||
# Input
|
||||
HEADERS += src/PluginsList.h \
|
||||
src/MainWindow.h \
|
||||
src/GraphManager.h \
|
||||
src/GraphDisplay.h \
|
||||
src/ElementProperties.h \
|
||||
src/PadProperties.h \
|
||||
src/PipelineIE.h \
|
||||
src/CustomSettings.h \
|
||||
src/SeekSlider.h
|
||||
|
||||
SOURCES += src/main.cpp \
|
||||
src/PluginsList.cpp \
|
||||
src/MainWindow.cpp \
|
||||
src/GraphManager.cpp \
|
||||
src/GraphDisplay.cpp \
|
||||
src/ElementProperties.cpp \
|
||||
src/PadProperties.cpp \
|
||||
src/PipelineIE.cpp \
|
||||
src/CustomSettings.cpp \
|
||||
src/SeekSlider.cpp
|
23
readme.md
Normal file
23
readme.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
pipeviz
|
||||
==========
|
||||
|
||||
Pipeviz is a graphedit for gstreamer-1.0. This is a gui tool for constructing and testing gstreamer pipelines.
|
||||
|
||||
It allows you:
|
||||
|
||||
* to construct the pipelines via the gui interface
|
||||
|
||||
* to test different types of pipes easy
|
||||
|
||||
* save and open your graphs
|
||||
|
||||
Who might be interested in it?
|
||||
|
||||
* quality assurance
|
||||
|
||||
* technical support
|
||||
|
||||
* software engineers
|
||||
|
||||
|
||||
![alt tag](https://cloud.githubusercontent.com/assets/10683398/6396608/94f89e3a-be09-11e4-982c-5bf3a57bc6f4.png)
|
38
src/CustomSettings.cpp
Normal file
38
src/CustomSettings.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include "CustomSettings.h"
|
||||
|
||||
#include <QSettings>
|
||||
|
||||
#define COMPANY_NAME "virinext"
|
||||
#define APPLICATION_NAME "pipeviz"
|
||||
|
||||
void CustomSettings::saveLastIODirectory(const QString &name)
|
||||
{
|
||||
QSettings settings(COMPANY_NAME, APPLICATION_NAME);
|
||||
settings.setValue("last_directory", name);
|
||||
}
|
||||
|
||||
|
||||
QString CustomSettings::lastIODirectory()
|
||||
{
|
||||
QSettings settings(COMPANY_NAME, APPLICATION_NAME);
|
||||
QString res = settings.value("last_directory").toString();
|
||||
|
||||
if(res.isEmpty())
|
||||
res = "./";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void CustomSettings::saveMainWindowGeometry(const QByteArray &geometry)
|
||||
{
|
||||
QSettings settings(COMPANY_NAME, APPLICATION_NAME);
|
||||
settings.setValue("geometry", geometry);
|
||||
}
|
||||
|
||||
|
||||
QByteArray CustomSettings::mainWindowGeometry()
|
||||
{
|
||||
QSettings settings(COMPANY_NAME, APPLICATION_NAME);
|
||||
return settings.value("geometry").toByteArray();
|
||||
}
|
19
src/CustomSettings.h
Normal file
19
src/CustomSettings.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef CUSTOM_SETTINGS_H_
|
||||
#define CUSTOM_SETTINGS_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
|
||||
namespace CustomSettings
|
||||
{
|
||||
void saveLastIODirectory(const QString &name);
|
||||
QString lastIODirectory();
|
||||
|
||||
void saveMainWindowGeometry(const QByteArray &geometry);
|
||||
QByteArray mainWindowGeometry();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
280
src/ElementProperties.cpp
Normal file
280
src/ElementProperties.cpp
Normal file
|
@ -0,0 +1,280 @@
|
|||
#include "ElementProperties.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QGridLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QString>
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QPushButton>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
ElementProperties::ElementProperties(QSharedPointer<GraphManager> pGraph, const char *name,
|
||||
QWidget *parent, Qt::WindowFlags flags):
|
||||
QWidget(parent, flags),
|
||||
m_pGraphManager(pGraph),
|
||||
m_name(name)
|
||||
{
|
||||
setWindowTitle(QString(name) + " properties");
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ElementProperties::create()
|
||||
{
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(m_pGraphManager -> m_pGraph), m_name.toStdString().c_str());
|
||||
|
||||
if(!element)
|
||||
return;
|
||||
|
||||
QGridLayout *play = new QGridLayout;
|
||||
|
||||
GParamSpec **prop_specs;
|
||||
guint num_props;
|
||||
|
||||
prop_specs = g_object_class_list_properties(G_OBJECT_GET_CLASS (element),
|
||||
&num_props);
|
||||
|
||||
for(std::size_t i = 0; i<num_props; i++)
|
||||
{
|
||||
bool readOnly = true;
|
||||
GParamSpec *param = prop_specs[i];
|
||||
GValue value = { 0 };
|
||||
|
||||
g_value_init (&value, param -> value_type);
|
||||
if(param -> flags & G_PARAM_READABLE)
|
||||
g_object_get_property (G_OBJECT(element), param -> name, &value);
|
||||
else
|
||||
{
|
||||
const GValue *valueDef = g_param_spec_get_default_value(param);
|
||||
g_value_copy(valueDef, &value);
|
||||
}
|
||||
|
||||
if(param->flags & G_PARAM_WRITABLE)
|
||||
readOnly = false;
|
||||
|
||||
QString propertyName = g_param_spec_get_name (param);
|
||||
QString propertyValue;
|
||||
|
||||
bool skip = false;
|
||||
|
||||
switch (G_VALUE_TYPE (&value))
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
{
|
||||
const char *string_val = g_value_get_string (&value);
|
||||
propertyValue = string_val;
|
||||
break;
|
||||
}
|
||||
case G_TYPE_BOOLEAN:
|
||||
{
|
||||
gboolean bool_val = g_value_get_boolean (&value);
|
||||
propertyValue = QString::number(bool_val);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_ULONG:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_ulong(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_LONG:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_long(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_uint(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_int(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT64:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_uint64(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT64:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_int64(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_FLOAT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_float(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_DOUBLE:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_double(&value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
skip = true;
|
||||
qDebug() << "property " << propertyName << " not supported";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
play -> addWidget(new QLabel(propertyName), i, 0);
|
||||
|
||||
QLineEdit *ple = new QLineEdit(propertyValue);
|
||||
ple -> setReadOnly(readOnly);
|
||||
play -> addWidget(ple, i, 1);
|
||||
if(!skip)
|
||||
m_values.insert(propertyName, ple);
|
||||
else
|
||||
ple -> setReadOnly(true);
|
||||
}
|
||||
|
||||
QVBoxLayout *pvblay = new QVBoxLayout;
|
||||
QWidget *pwgt = new QWidget(this);
|
||||
pwgt -> setLayout(play);
|
||||
QScrollArea *pscroll = new QScrollArea(this);
|
||||
pscroll -> setWidget(pwgt);
|
||||
|
||||
pvblay -> addWidget(pscroll);
|
||||
|
||||
QHBoxLayout *phblay = new QHBoxLayout;
|
||||
|
||||
QPushButton *pcmdApply = new QPushButton("Apply");
|
||||
QPushButton *pcmdOk = new QPushButton("OK");
|
||||
QPushButton *pcmdCancel = new QPushButton("Cancel");
|
||||
|
||||
|
||||
phblay -> addStretch(1);
|
||||
phblay -> addWidget(pcmdApply);
|
||||
phblay -> addWidget(pcmdCancel);
|
||||
phblay -> addWidget(pcmdOk);
|
||||
|
||||
pvblay -> addLayout(phblay);
|
||||
|
||||
QObject::connect(pcmdApply, SIGNAL(clicked()), this, SLOT(applyClicked()));
|
||||
QObject::connect(pcmdCancel, SIGNAL(clicked()), this, SLOT(close()));
|
||||
QObject::connect(pcmdOk, SIGNAL(clicked()), this, SLOT(okClicked()));
|
||||
|
||||
setLayout(pvblay);
|
||||
|
||||
g_free(prop_specs);
|
||||
gst_object_unref(element);
|
||||
|
||||
}
|
||||
|
||||
void ElementProperties::applyClicked()
|
||||
{
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(m_pGraphManager -> m_pGraph),
|
||||
m_name.toStdString().c_str());
|
||||
|
||||
if(!element)
|
||||
return;
|
||||
|
||||
QMap<QString, QLineEdit *>::iterator itr = m_values.begin();
|
||||
|
||||
for(;itr != m_values.end(); itr++)
|
||||
{
|
||||
GParamSpec *param = g_object_class_find_property(G_OBJECT_GET_CLASS (element),
|
||||
itr.key().toStdString().c_str());
|
||||
|
||||
if(!param)
|
||||
{
|
||||
qDebug() << "problem with setting " << itr.key() << " property";
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!(param -> flags & G_PARAM_WRITABLE))
|
||||
continue;
|
||||
|
||||
QString valStr = itr.value() -> text();
|
||||
std::string tmpStr = itr.key().toStdString();
|
||||
const char *propName = tmpStr.c_str();
|
||||
switch (param -> value_type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
{
|
||||
g_object_set(G_OBJECT(element), propName, valStr.toStdString().c_str(), NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_BOOLEAN:
|
||||
{
|
||||
gboolean val = valStr.toInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_ULONG:
|
||||
{
|
||||
gulong val = valStr.toULong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_LONG:
|
||||
{
|
||||
glong val = valStr.toLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT:
|
||||
{
|
||||
guint val = valStr.toUInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT:
|
||||
{
|
||||
gint val = valStr.toInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT64:
|
||||
{
|
||||
guint64 val = valStr.toULongLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT64:
|
||||
{
|
||||
gint64 val = valStr.toLongLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_FLOAT:
|
||||
{
|
||||
gfloat val = valStr.toFloat();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_DOUBLE:
|
||||
{
|
||||
gdouble val = valStr.toDouble();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
qDebug() << "property " << itr.key() << " not supported";
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gst_object_unref(element);
|
||||
|
||||
delete layout();
|
||||
qDeleteAll(children());
|
||||
|
||||
|
||||
create();
|
||||
}
|
||||
|
||||
void ElementProperties::okClicked()
|
||||
{
|
||||
applyClicked();
|
||||
close();
|
||||
}
|
33
src/ElementProperties.h
Normal file
33
src/ElementProperties.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#ifndef ELEMENT_PROPERTIES_H_
|
||||
#define ELEMENT_PROPERTIES_H_
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSharedPointer>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "GraphManager.h"
|
||||
|
||||
class ElementProperties: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ElementProperties(QSharedPointer<GraphManager> pGraphManager, const char *name,
|
||||
QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
|
||||
|
||||
private slots:
|
||||
void applyClicked();
|
||||
void okClicked();
|
||||
|
||||
private:
|
||||
QSharedPointer<GraphManager> m_pGraphManager;
|
||||
QMap<QString, QLineEdit *> m_values;
|
||||
QString m_name;
|
||||
|
||||
void create();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
960
src/GraphDisplay.cpp
Normal file
960
src/GraphDisplay.cpp
Normal file
|
@ -0,0 +1,960 @@
|
|||
#include "GraphDisplay.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <math.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QTableWidget>
|
||||
#include <QVariant>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "ElementProperties.h"
|
||||
#include "PadProperties.h"
|
||||
|
||||
#define PAD_SIZE 8
|
||||
#define PAD_SIZE_ACTION 16
|
||||
|
||||
|
||||
GraphDisplay::GraphDisplay(QWidget *parent, Qt::WindowFlags f):
|
||||
QWidget(parent, f)
|
||||
{
|
||||
setFocusPolicy(Qt::WheelFocus);
|
||||
}
|
||||
|
||||
void GraphDisplay::updateDisplayInfoIds()
|
||||
{
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
for(std::size_t j=0; j<m_displayInfo.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_name == m_displayInfo[j].m_name)
|
||||
{
|
||||
m_displayInfo[j].m_id = m_info[i].m_id;
|
||||
for(std::size_t k=0; k<m_displayInfo.size(); k++)
|
||||
{
|
||||
if(k != j && m_displayInfo[j].m_id == m_displayInfo[k].m_id)
|
||||
m_displayInfo[k].m_id = (size_t)-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::update(const std::vector <ElementInfo> &info)
|
||||
{
|
||||
bool needUpdate = false;
|
||||
|
||||
if(m_info.size() != info.size())
|
||||
needUpdate = true;
|
||||
|
||||
if(!needUpdate)
|
||||
{
|
||||
for(std::size_t i=0; i<info.size(); i++)
|
||||
{
|
||||
std::size_t j=0;
|
||||
|
||||
for(; j<m_info.size(); j++)
|
||||
{
|
||||
if(info[i].m_name == m_info[j].m_name)
|
||||
break;
|
||||
}
|
||||
|
||||
if(j == m_info.size())
|
||||
{
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(info[i].m_pads != m_info[j].m_pads)
|
||||
{
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(info[i].m_connections != m_info[j].m_connections)
|
||||
{
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(needUpdate)
|
||||
{
|
||||
m_info = info;
|
||||
updateDisplayInfoIds();
|
||||
calculatePositions();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
QPen defaultPen = painter.pen();
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(m_displayInfo[i].m_isSelected)
|
||||
painter.setPen(QPen(Qt::blue));
|
||||
|
||||
painter.drawRect(m_displayInfo[i].m_rect);
|
||||
|
||||
painter.setPen(defaultPen);
|
||||
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
|
||||
QPoint point = getPadPosition(m_info[i].m_id, m_info[i].m_pads[j].m_id);
|
||||
|
||||
int xPos, yPos;
|
||||
xPos = point.x();
|
||||
yPos = point.y();
|
||||
|
||||
xPos -= PAD_SIZE / 2;
|
||||
yPos -= PAD_SIZE / 2;
|
||||
|
||||
painter.fillRect(xPos, yPos, PAD_SIZE, PAD_SIZE, Qt::black);
|
||||
|
||||
QPoint textPos;
|
||||
|
||||
QRect rect = painter.boundingRect(0, 0, width(), height(), Qt::AlignLeft | Qt::AlignTop, QString(m_info[i].m_pads[j].m_name.c_str()));
|
||||
if(m_info[i].m_pads[j].m_type == PadInfo::Out)
|
||||
textPos = QPoint(point.x() - PAD_SIZE - rect.width(), point.y() + PAD_SIZE / 2);
|
||||
else if(m_info[i].m_pads[j].m_type == PadInfo::In)
|
||||
textPos = QPoint(point.x() + PAD_SIZE, point.y() + PAD_SIZE / 2);
|
||||
painter.drawText(textPos, QString(m_info[i].m_pads[j].m_name.c_str()));
|
||||
|
||||
if(m_info[i].m_connections[j].m_elementId != ((size_t)-1) && m_info[i].m_connections[j].m_padId != ((size_t)-1))
|
||||
{
|
||||
xPos = point.x();
|
||||
yPos = point.y();
|
||||
|
||||
point = getPadPosition(m_info[i].m_connections[j].m_elementId, m_info[i].m_connections[j].m_padId);
|
||||
int xPosPeer, yPosPeer;
|
||||
|
||||
xPosPeer = point.x();
|
||||
yPosPeer = point.y();
|
||||
|
||||
painter.drawLine(xPos, yPos, xPosPeer, yPosPeer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
painter.drawText(m_displayInfo[i].m_rect.topLeft() + QPoint(10, 15), QString(m_displayInfo[i].m_name.c_str()));
|
||||
}
|
||||
|
||||
if(m_moveInfo.m_action == MakeConnect)
|
||||
{
|
||||
painter.drawLine(m_moveInfo.m_position, m_moveInfo.m_startPosition);
|
||||
}
|
||||
else if(m_moveInfo.m_action == Select)
|
||||
{
|
||||
if(!m_moveInfo.m_position.isNull())
|
||||
{
|
||||
painter.setPen(Qt::DashLine);
|
||||
painter.drawRect(QRect(m_moveInfo.m_startPosition, m_moveInfo.m_position));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GraphDisplay::ElementDisplayInfo GraphDisplay::calculateOnePosition(const ElementInfo &info)
|
||||
{
|
||||
ElementDisplayInfo displayInfo;
|
||||
displayInfo.m_id = info.m_id;
|
||||
displayInfo.m_name = info.m_name;
|
||||
displayInfo.m_isSelected = false;
|
||||
|
||||
int width = 150;
|
||||
int height = 50;
|
||||
|
||||
int numInPads, numOutPads;
|
||||
numInPads = numOutPads = 0;
|
||||
|
||||
for(std::size_t j=0; j<info.m_pads.size(); j++)
|
||||
{
|
||||
if(info.m_pads[j].m_type == PadInfo::Out)
|
||||
numOutPads++;
|
||||
else if(info.m_pads[j].m_type == PadInfo::In)
|
||||
numInPads++;
|
||||
}
|
||||
|
||||
if(std::max(numInPads, numOutPads) >= 1)
|
||||
height += (std::max(numInPads, numOutPads) - 1) * 25;
|
||||
|
||||
int curX, curY;
|
||||
curX = curY = 10;
|
||||
|
||||
QRect rect(curX, curY, width, height);
|
||||
|
||||
while(true)
|
||||
{
|
||||
rect = QRect(curX, curY, width, height);
|
||||
QRect rectTest(curX, curY - 15, width + 15, height + 15);
|
||||
bool noIntersects = true;
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(rectTest.intersects(m_displayInfo[i].m_rect))
|
||||
{
|
||||
noIntersects = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(noIntersects)
|
||||
break;
|
||||
|
||||
curY += 25;
|
||||
}
|
||||
|
||||
displayInfo.m_rect = rect;
|
||||
|
||||
return displayInfo;
|
||||
|
||||
}
|
||||
|
||||
void GraphDisplay::calculatePositions()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
std::size_t j=0;
|
||||
for(; j<m_info.size(); j++)
|
||||
{
|
||||
if(m_displayInfo[i].m_id == m_info[j].m_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if(j == m_info.size())
|
||||
{
|
||||
m_displayInfo.erase(m_displayInfo.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i >= m_displayInfo.size())
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
std::size_t i=0;
|
||||
for(; i<m_info.size(); i++)
|
||||
{
|
||||
std::size_t j=0;
|
||||
for(; j<m_displayInfo.size(); j++)
|
||||
{
|
||||
if(m_displayInfo[j].m_id == m_info[i].m_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if(j == m_displayInfo.size())
|
||||
m_displayInfo.push_back(calculateOnePosition(m_info[i]));
|
||||
}
|
||||
|
||||
std::vector <ElementDisplayInfo> reorderedDisplayInfo(m_info.size());
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
for(std::size_t j=0; j<m_displayInfo.size(); j++)
|
||||
{
|
||||
if(m_displayInfo[j].m_id == m_info[i].m_id)
|
||||
{
|
||||
reorderedDisplayInfo[i] = m_displayInfo[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_displayInfo = reorderedDisplayInfo;
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
std::size_t elementId, padId;
|
||||
getIdByPosition(event -> pos(), elementId, padId);
|
||||
|
||||
|
||||
if(event -> buttons() & Qt::RightButton)
|
||||
{
|
||||
showContextMenu(event);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(padId != ((size_t)-1))
|
||||
{
|
||||
m_moveInfo.m_padId = padId;
|
||||
m_moveInfo.m_elementId = elementId;
|
||||
m_moveInfo.m_position = event -> pos();
|
||||
m_moveInfo.m_action = MakeConnect;
|
||||
m_moveInfo.m_startPosition = event -> pos();
|
||||
}
|
||||
else if(elementId != ((size_t)-1))
|
||||
{
|
||||
m_moveInfo.m_elementId = elementId;
|
||||
m_moveInfo.m_padId = -1;
|
||||
m_moveInfo.m_position = event -> pos();
|
||||
m_moveInfo.m_action = MoveComponent;
|
||||
m_moveInfo.m_startPosition = event -> pos();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveInfo.m_startPosition = event -> pos();
|
||||
m_moveInfo.m_action = Select;
|
||||
m_moveInfo.m_position = QPoint();
|
||||
}
|
||||
}
|
||||
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
m_displayInfo[i].m_isSelected = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GraphDisplay::mouseReleaseEvent (QMouseEvent *event)
|
||||
{
|
||||
if(m_moveInfo.m_action == MakeConnect)
|
||||
{
|
||||
std::size_t elementId, padId;
|
||||
getIdByPosition(event -> pos(), elementId, padId);
|
||||
|
||||
if(elementId != ((size_t)-1) && padId != ((size_t)-1))
|
||||
{
|
||||
ElementInfo infoSrc, infoDst;
|
||||
const char *srcPad, *dstPad;
|
||||
srcPad = NULL;
|
||||
dstPad = NULL;
|
||||
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == m_moveInfo.m_elementId)
|
||||
{
|
||||
infoSrc = m_info[i];
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_id == m_moveInfo.m_padId)
|
||||
{
|
||||
srcPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(m_info[i].m_id == elementId)
|
||||
{
|
||||
infoDst = m_info[i];
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_id == padId)
|
||||
{
|
||||
dstPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(srcPad != NULL && dstPad != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(srcPad != NULL && dstPad != NULL);
|
||||
|
||||
qDebug() << "Connection from " << infoSrc.m_name.c_str() << ":" << srcPad
|
||||
<< " to " << infoDst.m_name.c_str() << ":" << dstPad;
|
||||
|
||||
if(!m_pGraph -> Connect(infoSrc.m_name.c_str(), srcPad, infoDst.m_name.c_str(), dstPad))
|
||||
{
|
||||
QString msg;
|
||||
msg = "Connection ";
|
||||
msg += QString(infoSrc.m_name.c_str()) + ":" + srcPad;
|
||||
msg += " => ";
|
||||
msg += QString(infoDst.m_name.c_str()) + ":" + dstPad;
|
||||
msg += " was FAILED";
|
||||
|
||||
QMessageBox::warning(this, "Coonection failed", msg);
|
||||
}
|
||||
m_info = m_pGraph -> GetInfo();
|
||||
updateDisplayInfoIds();
|
||||
}
|
||||
}
|
||||
else if(m_moveInfo.m_action == Select)
|
||||
{
|
||||
std::size_t width = std::abs(m_moveInfo.m_position.x() - m_moveInfo.m_startPosition.x());
|
||||
std::size_t height = std::abs(m_moveInfo.m_position.y() - m_moveInfo.m_startPosition.y());
|
||||
|
||||
if(!m_moveInfo.m_position.isNull() && width * height > 5)
|
||||
{
|
||||
QRect selectionRect(m_moveInfo.m_startPosition, m_moveInfo.m_position);
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(selectionRect.intersects(m_displayInfo[i].m_rect))
|
||||
m_displayInfo[i].m_isSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
else if(m_moveInfo.m_action == MoveComponent)
|
||||
{
|
||||
int dx = event -> x() - m_moveInfo.m_startPosition.x();
|
||||
int dy = event -> y() - m_moveInfo.m_startPosition.y();
|
||||
|
||||
if(dx == dy && dy == 0)
|
||||
{
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(m_displayInfo[i].m_id == m_moveInfo.m_elementId)
|
||||
{
|
||||
m_displayInfo[i].m_isSelected = true;
|
||||
repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_moveInfo.m_action = None;
|
||||
m_moveInfo.m_elementId = -1;
|
||||
m_moveInfo.m_padId = -1;
|
||||
m_moveInfo.m_startPosition = QPoint();
|
||||
m_moveInfo.m_position = QPoint();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if(m_moveInfo.m_action == MoveComponent)
|
||||
{
|
||||
int dx = event -> x() - m_moveInfo.m_position.x();
|
||||
int dy = event -> y() - m_moveInfo.m_position.y();
|
||||
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(m_displayInfo[i].m_id == m_moveInfo.m_elementId)
|
||||
{
|
||||
QRect newRect = m_displayInfo[i].m_rect;
|
||||
newRect.adjust(dx, dy, dx, dy);
|
||||
|
||||
if(contentsRect().contains(newRect))
|
||||
m_displayInfo[i].m_rect = newRect;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(m_moveInfo.m_action != None)
|
||||
{
|
||||
m_moveInfo.m_position = event -> pos();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GraphDisplay::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if(event -> key() == Qt::Key_Delete)
|
||||
removeSelected();
|
||||
|
||||
return QWidget::keyPressEvent(event);
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::showContextMenu(QMouseEvent *event)
|
||||
{
|
||||
QMenu menu;
|
||||
|
||||
std::size_t elementId, padId;
|
||||
getIdByPosition(event -> pos(), elementId, padId);
|
||||
|
||||
GstState state;
|
||||
GstStateChangeReturn res = gst_element_get_state (m_pGraph -> m_pGraph, &state, NULL, GST_MSECOND);
|
||||
|
||||
bool isActive = false;
|
||||
|
||||
if(res != GST_STATE_CHANGE_SUCCESS || state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
|
||||
isActive = true;
|
||||
|
||||
bool hasSelection = false;
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
if(m_displayInfo[i].m_isSelected)
|
||||
hasSelection = true;
|
||||
|
||||
if(hasSelection)
|
||||
{
|
||||
QAction *pact = menu.addAction("Remove selected");
|
||||
if(isActive)
|
||||
pact -> setDisabled(true);
|
||||
|
||||
}
|
||||
else if(padId != ((size_t)-1))
|
||||
menu.addAction("Pad properties");
|
||||
else if(elementId != ((size_t)-1))
|
||||
{
|
||||
menu.addAction("Element properties");
|
||||
QAction *pact = menu.addAction("Remove");
|
||||
|
||||
if(isActive)
|
||||
pact -> setDisabled(true);
|
||||
|
||||
pact = menu.addAction("Request pad...");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
for(std::size_t j=0; j<m_info[i].m_connections.size(); j++)
|
||||
{
|
||||
|
||||
QPoint point = getPadPosition(m_info[i].m_id, m_info[i].m_pads[j].m_id);
|
||||
|
||||
double x1, y1;
|
||||
x1 = point.x();
|
||||
y1 = point.y();
|
||||
|
||||
if(m_info[i].m_connections[j].m_elementId != ((size_t)-1) && m_info[i].m_connections[j].m_padId != ((size_t)-1))
|
||||
{
|
||||
point = getPadPosition(m_info[i].m_connections[j].m_elementId, m_info[i].m_connections[j].m_padId);
|
||||
double x2, y2;
|
||||
|
||||
x2 = point.x();
|
||||
y2 = point.y();
|
||||
|
||||
double dy = y2 - y1;
|
||||
double dx = x2 - x1;
|
||||
|
||||
double x0 = event -> pos().x();
|
||||
double y0 = event -> pos().y();
|
||||
|
||||
double distance = std::abs((int)(dy * x0 - dx * y0 + x2 * y1 - y2 * x1));
|
||||
distance = distance / sqrt(dy * dy + dx * dx);
|
||||
|
||||
if(distance < 5)
|
||||
{
|
||||
elementId = m_info[i].m_id;
|
||||
padId = m_info[i].m_pads[j].m_id;
|
||||
|
||||
QAction *pact = menu.addAction("Disconnect");
|
||||
|
||||
if(isActive)
|
||||
pact -> setDisabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!menu.isEmpty())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!menu.isEmpty())
|
||||
{
|
||||
QAction *pact = menu.exec(event -> globalPos());
|
||||
if(pact)
|
||||
{
|
||||
if(pact -> text() == "Remove")
|
||||
removePlugin(elementId);
|
||||
else if(pact -> text() == "Element properties")
|
||||
showElementProperties(elementId);
|
||||
else if(pact -> text() == "Pad properties")
|
||||
showPadProperties(elementId, padId);
|
||||
else if(pact -> text() == "Disconnect")
|
||||
disconnect(elementId, padId);
|
||||
else if(pact -> text() == "Request pad...")
|
||||
requestPad(elementId);
|
||||
else if(pact -> text() == "Remove selected")
|
||||
removeSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::removeSelected()
|
||||
{
|
||||
GstState state;
|
||||
GstStateChangeReturn res = gst_element_get_state (m_pGraph -> m_pGraph, &state, NULL, GST_MSECOND);
|
||||
|
||||
if(res != GST_STATE_CHANGE_SUCCESS || state == GST_STATE_PAUSED || state == GST_STATE_PLAYING)
|
||||
return;
|
||||
|
||||
while(true)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(m_displayInfo[i].m_isSelected)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i != m_displayInfo.size())
|
||||
removePlugin(m_displayInfo[i].m_id);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDisplay::removePlugin(std::size_t id)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == id)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i < m_info.size())
|
||||
{
|
||||
if(m_pGraph -> RemovePlugin(m_info[i].m_name.c_str()))
|
||||
{
|
||||
std::vector<ElementInfo> info = m_pGraph -> GetInfo();
|
||||
update(info);
|
||||
}
|
||||
else
|
||||
QMessageBox::warning(this, "Element removing problem", "Element `" + QString(m_info[i].m_name.c_str()) + "` remowing was FAILED");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::showElementProperties(std::size_t id)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == id)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i < m_info.size())
|
||||
{
|
||||
ElementProperties *pprops = new ElementProperties(m_pGraph, m_info[i].m_name.c_str());
|
||||
pprops -> setAttribute(Qt::WA_QuitOnClose, false);
|
||||
pprops -> show();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDisplay::showPadProperties(std::size_t elementId, std::size_t padId)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == elementId)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i < m_info.size())
|
||||
{
|
||||
std::size_t j=0;
|
||||
for(; j<m_info[i].m_pads.size(); j++)
|
||||
if(m_info[i].m_pads[j].m_id == padId)
|
||||
break;
|
||||
|
||||
if(j < m_info[i].m_pads.size())
|
||||
{
|
||||
PadProperties *pprops = new PadProperties(m_pGraph, m_info[i].m_name.c_str(), m_info[i].m_pads[j].m_name.c_str());
|
||||
pprops -> setAttribute(Qt::WA_QuitOnClose, false);
|
||||
pprops -> show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphDisplay::disconnect(size_t elementId, size_t padId)
|
||||
{
|
||||
std::string src, dst, srcPad, dstPad;
|
||||
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == elementId)
|
||||
{
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_id == padId)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_type == PadInfo::Out)
|
||||
{
|
||||
src = m_info[i].m_name;
|
||||
srcPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
elementId = m_info[i].m_connections[j].m_elementId;
|
||||
padId = m_info[i].m_connections[j].m_padId;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = m_info[i].m_name;
|
||||
dstPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
elementId = m_info[i].m_connections[j].m_elementId;
|
||||
padId = m_info[i].m_connections[j].m_padId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == elementId)
|
||||
{
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_id == padId)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_type == PadInfo::Out)
|
||||
{
|
||||
src = m_info[i].m_name;
|
||||
srcPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = m_info[i].m_name;
|
||||
dstPad = m_info[i].m_pads[j].m_name.c_str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "Disconnect " << src.c_str() << ":" << srcPad.c_str()
|
||||
<< " <-> " << dst.c_str() << ":" << dstPad.c_str();
|
||||
|
||||
if(src.empty() || dst.empty() || srcPad.empty() || dstPad.empty())
|
||||
return;
|
||||
|
||||
|
||||
m_pGraph -> Disconnect(src.c_str(), srcPad.c_str(), dst.c_str(), dstPad.c_str());
|
||||
|
||||
m_info = m_pGraph -> GetInfo();
|
||||
updateDisplayInfoIds();
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
void GraphDisplay::requestPad(std::size_t elementId)
|
||||
{
|
||||
QStringList labels;
|
||||
labels.push_back("Template name");
|
||||
labels.push_back("Caps");
|
||||
labels.push_back("Direction");
|
||||
|
||||
QTableWidget *ptwgt = new QTableWidget();
|
||||
ptwgt -> setColumnCount(3);
|
||||
ptwgt -> setHorizontalHeaderLabels(labels);
|
||||
ptwgt -> setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
ptwgt -> setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
|
||||
GstElement *element = NULL;
|
||||
for(std::size_t i=0; i<m_info.size(); i++)
|
||||
{
|
||||
if(m_info[i].m_id == elementId)
|
||||
{
|
||||
element = gst_bin_get_by_name(GST_BIN(m_pGraph -> m_pGraph), m_info[i].m_name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!element)
|
||||
{
|
||||
QMessageBox::warning(this, "Request pad failed", "Request pad list obtaining was failed");
|
||||
return;
|
||||
}
|
||||
|
||||
GstElementClass *klass;
|
||||
klass = GST_ELEMENT_GET_CLASS(element);
|
||||
|
||||
GList *lst = gst_element_class_get_pad_template_list(klass);
|
||||
|
||||
std::size_t k = 0;
|
||||
while (lst != NULL)
|
||||
{
|
||||
GstPadTemplate *templ;
|
||||
templ = (GstPadTemplate *) lst -> data;
|
||||
|
||||
if(GST_PAD_TEMPLATE_PRESENCE(templ) == GST_PAD_REQUEST)
|
||||
{
|
||||
ptwgt -> setRowCount(k + 1);
|
||||
ptwgt -> setItem(k, 0, new QTableWidgetItem(GST_PAD_TEMPLATE_NAME_TEMPLATE(templ)));
|
||||
|
||||
GstCaps *caps = gst_pad_template_get_caps(templ);
|
||||
gchar *capsStr = gst_caps_to_string(caps);
|
||||
ptwgt -> setItem(k, 1, new QTableWidgetItem(capsStr));
|
||||
g_free(capsStr);
|
||||
gst_caps_unref(caps);
|
||||
|
||||
const char *directionSrc = "SRC";
|
||||
const char *directionSink = "SINK";
|
||||
const char *directionUnknown = "UNKNOWN";
|
||||
|
||||
QString direction;
|
||||
switch(GST_PAD_TEMPLATE_DIRECTION(templ))
|
||||
{
|
||||
case GST_PAD_UNKNOWN:
|
||||
direction = directionUnknown;
|
||||
break;
|
||||
|
||||
case GST_PAD_SRC:
|
||||
direction = directionSrc;
|
||||
break;
|
||||
|
||||
case GST_PAD_SINK:
|
||||
direction = directionSink;
|
||||
break;
|
||||
};
|
||||
|
||||
ptwgt -> setItem(k, 2, new QTableWidgetItem(direction));
|
||||
k++;
|
||||
}
|
||||
|
||||
lst = g_list_next(lst);
|
||||
}
|
||||
|
||||
qulonglong v((qulonglong)element);
|
||||
ptwgt -> setProperty("element", v);
|
||||
|
||||
connect(ptwgt, SIGNAL(cellActivated(int, int)), SLOT(addRequestPad(int, int)));
|
||||
|
||||
ptwgt -> setAttribute(Qt::WA_QuitOnClose, false);
|
||||
ptwgt -> show();
|
||||
}
|
||||
|
||||
void GraphDisplay::addRequestPad(int row, int collumn)
|
||||
{
|
||||
QTableWidget *ptwgt = dynamic_cast<QTableWidget *> (QObject::sender());
|
||||
|
||||
qulonglong v = ptwgt -> property("element").toULongLong();
|
||||
GstElement *element = (GstElement *) v;
|
||||
GstElementClass *klass = GST_ELEMENT_GET_CLASS(element);
|
||||
|
||||
GstPadTemplate *templ = gst_element_class_get_pad_template(klass, ptwgt -> itemAt(row, 0) -> text().toStdString().c_str());
|
||||
|
||||
gst_element_request_pad(element, templ, NULL, NULL);
|
||||
|
||||
gst_object_unref(element);
|
||||
ptwgt -> close();
|
||||
|
||||
std::vector<ElementInfo> info = m_pGraph -> GetInfo();
|
||||
update(info);
|
||||
|
||||
}
|
||||
|
||||
void GraphDisplay::getIdByPosition(const QPoint &pos, std::size_t &elementId, std::size_t &padId)
|
||||
{
|
||||
std::size_t i=0;
|
||||
elementId = padId = -1;
|
||||
for(; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(elementId != ((size_t)-1))
|
||||
break;
|
||||
|
||||
QRect rect(
|
||||
m_displayInfo[i].m_rect.x() - 8,
|
||||
m_displayInfo[i].m_rect.y() - 6,
|
||||
m_displayInfo[i].m_rect.width() + 16,
|
||||
m_displayInfo[i].m_rect.height() + 12
|
||||
);
|
||||
if(rect.contains(pos))
|
||||
{
|
||||
std::size_t j=0;
|
||||
for(; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
QPoint point = getPadPosition(m_displayInfo[i].m_id, m_info[i].m_pads[j].m_id);
|
||||
|
||||
int xPos, yPos;
|
||||
xPos = point.x();
|
||||
yPos = point.y();
|
||||
|
||||
xPos -= PAD_SIZE_ACTION / 2;
|
||||
yPos -= PAD_SIZE_ACTION / 2;
|
||||
|
||||
QRect rect(xPos, yPos, PAD_SIZE_ACTION, PAD_SIZE_ACTION);
|
||||
if(rect.contains(pos))
|
||||
{
|
||||
padId = m_info[i].m_pads[j].m_id;
|
||||
elementId = m_displayInfo[i].m_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(j == m_info[i].m_pads.size())
|
||||
{
|
||||
if(m_displayInfo[i].m_rect.contains(pos))
|
||||
elementId = m_displayInfo[i].m_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QPoint GraphDisplay::getPadPosition(std::size_t elementId, std::size_t padId)
|
||||
{
|
||||
QPoint res;
|
||||
if(elementId == ((size_t)-1) || padId == ((size_t)-1))
|
||||
return res;
|
||||
|
||||
for(std::size_t i=0; i<m_displayInfo.size(); i++)
|
||||
{
|
||||
if(m_displayInfo[i].m_id == elementId)
|
||||
{
|
||||
int numInPads, numOutPads;
|
||||
numInPads = numOutPads = 0;
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
if(m_info[i].m_pads[j].m_type == PadInfo::Out)
|
||||
numOutPads++;
|
||||
else if(m_info[i].m_pads[j].m_type == PadInfo::In)
|
||||
numInPads++;
|
||||
}
|
||||
|
||||
int inDelta, outDelta, inPos, outPos;
|
||||
|
||||
inDelta = m_displayInfo[i].m_rect.height() / (numInPads + 1);
|
||||
outDelta = m_displayInfo[i].m_rect.height() / (numOutPads + 1);
|
||||
|
||||
inPos = inDelta;
|
||||
outPos = outDelta;
|
||||
for(std::size_t j=0; j<m_info[i].m_pads.size(); j++)
|
||||
{
|
||||
int xPos, yPos;
|
||||
yPos = m_displayInfo[i].m_rect.topRight().y();
|
||||
|
||||
if(m_info[i].m_pads[j].m_type == PadInfo::Out)
|
||||
{
|
||||
xPos = m_displayInfo[i].m_rect.topRight().x();
|
||||
yPos += outPos;
|
||||
outPos += outDelta;
|
||||
}
|
||||
else if(m_info[i].m_pads[j].m_type == PadInfo::In)
|
||||
{
|
||||
xPos = m_displayInfo[i].m_rect.topLeft().x();
|
||||
yPos += inPos;
|
||||
inPos += inDelta;
|
||||
}
|
||||
|
||||
if(m_info[i].m_pads[j].m_id == padId)
|
||||
{
|
||||
res = QPoint(xPos, yPos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
89
src/GraphDisplay.h
Normal file
89
src/GraphDisplay.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
#ifndef GRAPH_DISPLAY_H_
|
||||
#define GRAPH_DISPLAY_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSharedPointer>
|
||||
#include <QPoint>
|
||||
|
||||
|
||||
#include "GraphManager.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
|
||||
class GraphDisplay: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphDisplay(QWidget *parent=0, Qt::WindowFlags f=0);
|
||||
void update(const std::vector <ElementInfo> &info);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
|
||||
QSharedPointer<GraphManager> m_pGraph;
|
||||
|
||||
private slots:
|
||||
void addRequestPad(int row, int collumn);
|
||||
|
||||
private:
|
||||
|
||||
enum MoveAction
|
||||
{
|
||||
None = 0,
|
||||
MoveComponent,
|
||||
MakeConnect,
|
||||
Select
|
||||
};
|
||||
|
||||
struct MoveInfo
|
||||
{
|
||||
MoveInfo(): m_action(None)
|
||||
{
|
||||
}
|
||||
|
||||
MoveAction m_action;
|
||||
size_t m_elementId;
|
||||
size_t m_padId;
|
||||
QPoint m_position;
|
||||
QPoint m_startPosition;
|
||||
};
|
||||
|
||||
|
||||
struct ElementDisplayInfo
|
||||
{
|
||||
QRect m_rect;
|
||||
size_t m_id;
|
||||
std::string m_name;
|
||||
bool m_isSelected;
|
||||
};
|
||||
|
||||
void calculatePositions();
|
||||
void updateDisplayInfoIds();
|
||||
ElementDisplayInfo calculateOnePosition(const ElementInfo &info);
|
||||
void showContextMenu(QMouseEvent *event);
|
||||
void showElementProperties(std::size_t id);
|
||||
void showPadProperties(std::size_t elementId, std::size_t padId);
|
||||
void removePlugin(std::size_t id);
|
||||
void removeSelected();
|
||||
void getIdByPosition(const QPoint &pos, std::size_t &elementId, std::size_t &padId);
|
||||
QPoint getPadPosition(std::size_t elementId, std::size_t padId);
|
||||
void disconnect(std::size_t elementId, std::size_t padId);
|
||||
void requestPad(std::size_t elementId);
|
||||
|
||||
std::vector <ElementInfo> m_info;
|
||||
std::vector <ElementDisplayInfo> m_displayInfo;
|
||||
|
||||
MoveInfo m_moveInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
384
src/GraphManager.cpp
Normal file
384
src/GraphManager.cpp
Normal file
|
@ -0,0 +1,384 @@
|
|||
#include "GraphManager.h"
|
||||
#include <QDebug>
|
||||
|
||||
#include <QString>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "CustomSettings.h"
|
||||
|
||||
GraphManager::GraphManager()
|
||||
{
|
||||
m_pGraph = gst_pipeline_new ("pipeline");
|
||||
}
|
||||
|
||||
|
||||
GraphManager::~GraphManager()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::AddPlugin(const char *plugin, const char *name)
|
||||
{
|
||||
GstElement *pel = gst_element_factory_make(plugin, name);
|
||||
if(!pel)
|
||||
return false;
|
||||
|
||||
if(GST_IS_URI_HANDLER(pel))
|
||||
{
|
||||
static const gchar *const *protocols;
|
||||
protocols = gst_uri_handler_get_protocols(GST_URI_HANDLER(pel));
|
||||
|
||||
bool isFile = false;
|
||||
|
||||
for(std::size_t i=0; protocols[i] != NULL; i++)
|
||||
{
|
||||
if(strcmp("file", protocols[i]) == 0)
|
||||
{
|
||||
isFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(isFile)
|
||||
{
|
||||
QString path;
|
||||
QString dir = CustomSettings::lastIODirectory();
|
||||
|
||||
if(gst_uri_handler_get_uri_type(GST_URI_HANDLER(pel)) == GST_URI_SRC)
|
||||
path = QFileDialog::getOpenFileName(NULL, "Open Source File...", dir);
|
||||
else
|
||||
path = QFileDialog::getSaveFileName(NULL, "Open Sink File...", dir);
|
||||
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
gchar *uri = gst_filename_to_uri(path.toStdString().c_str(), NULL);
|
||||
if(uri)
|
||||
{
|
||||
qDebug() << "Set uri: " << uri;
|
||||
gst_uri_handler_set_uri(GST_URI_HANDLER(pel), uri, NULL);
|
||||
g_free(uri);
|
||||
|
||||
QString dir = QFileInfo(path).absoluteDir().absolutePath();
|
||||
CustomSettings::saveLastIODirectory(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QString uri = QInputDialog::getText(NULL, "Uri...", "Uri:");
|
||||
|
||||
if(!uri.isEmpty())
|
||||
{
|
||||
qDebug() << "Set uri: " << uri;
|
||||
gst_uri_handler_set_uri(GST_URI_HANDLER(pel), uri.toStdString().c_str(), NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool res = gst_bin_add(GST_BIN(m_pGraph), pel);
|
||||
if(res)
|
||||
gst_element_sync_state_with_parent(pel);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::RemovePlugin(const char *name)
|
||||
{
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(m_pGraph), name);
|
||||
|
||||
if(!element)
|
||||
return false;
|
||||
|
||||
bool res = gst_bin_remove (GST_BIN(m_pGraph), element);
|
||||
gst_object_unref(element);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::OpenUri(const char *uri, const char *name)
|
||||
{
|
||||
GstElement *element = gst_element_make_from_uri(GST_URI_SRC, uri, name, NULL);
|
||||
if(!element)
|
||||
return false;
|
||||
|
||||
bool res = gst_bin_add(GST_BIN(m_pGraph), element);
|
||||
if(res)
|
||||
gst_element_sync_state_with_parent(element);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::Connect(const char *srcElement, const char *srcPad,
|
||||
const char *dstElement, const char *dstPad)
|
||||
{
|
||||
GstElement *src = gst_bin_get_by_name (GST_BIN(m_pGraph), srcElement);
|
||||
GstElement *dst = gst_bin_get_by_name (GST_BIN(m_pGraph), dstElement);
|
||||
|
||||
bool res = gst_element_link_pads(src, srcPad, dst, dstPad);
|
||||
|
||||
gboolean seekRes = gst_element_seek_simple(m_pGraph, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, 0);
|
||||
|
||||
gst_object_unref(src);
|
||||
gst_object_unref(dst);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GraphManager::Disconnect(const char *srcElement, const char *srcPad,
|
||||
const char *dstElement, const char *dstPad)
|
||||
{
|
||||
GstElement *src = gst_bin_get_by_name (GST_BIN(m_pGraph), srcElement);
|
||||
GstElement *dst = gst_bin_get_by_name (GST_BIN(m_pGraph), dstElement);
|
||||
|
||||
|
||||
gst_element_unlink_pads(src, srcPad, dst, dstPad);
|
||||
|
||||
gst_object_unref(src);
|
||||
gst_object_unref(dst);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector <ElementInfo> GraphManager::GetInfo()
|
||||
{
|
||||
std::vector <ElementInfo> res;
|
||||
|
||||
GstIterator *iter;
|
||||
iter = gst_bin_iterate_elements (GST_BIN (m_pGraph));
|
||||
bool done = false;
|
||||
size_t id = 0;
|
||||
while (!done)
|
||||
{
|
||||
GValue value = { 0 };
|
||||
switch (gst_iterator_next (iter, &value))
|
||||
{
|
||||
case GST_ITERATOR_OK:
|
||||
{
|
||||
ElementInfo elementInfo;
|
||||
|
||||
elementInfo.m_id = id;
|
||||
id++;
|
||||
GstElement *element = GST_ELEMENT(g_value_get_object(&value));
|
||||
|
||||
gchar *name = gst_element_get_name(element);
|
||||
elementInfo.m_name = name;
|
||||
g_free(name);
|
||||
|
||||
GstElementFactory *pfactory =
|
||||
gst_element_get_factory(element);
|
||||
|
||||
elementInfo.m_pluginName =
|
||||
gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(pfactory));
|
||||
|
||||
GstIterator *padItr = gst_element_iterate_pads (element);
|
||||
bool padDone = FALSE;
|
||||
std::size_t padId = 0;
|
||||
while (!padDone)
|
||||
{
|
||||
GValue padVal = { 0 };
|
||||
switch (gst_iterator_next (padItr, &padVal))
|
||||
{
|
||||
case GST_ITERATOR_OK:
|
||||
{
|
||||
GstPad *pad = GST_PAD(g_value_get_object(&padVal));
|
||||
|
||||
PadInfo padInfo;
|
||||
padInfo.m_id = padId;
|
||||
|
||||
gchar *pad_name = gst_pad_get_name(pad);
|
||||
padInfo.m_name = pad_name;
|
||||
g_free(pad_name);
|
||||
|
||||
GstPadDirection direction = gst_pad_get_direction(pad);
|
||||
if(direction == GST_PAD_SRC)
|
||||
padInfo.m_type = PadInfo::Out;
|
||||
else if(direction == GST_PAD_SINK)
|
||||
padInfo.m_type = PadInfo::In;
|
||||
else
|
||||
padInfo.m_type = PadInfo::None;
|
||||
|
||||
elementInfo.m_pads.push_back(padInfo);
|
||||
g_value_reset (&padVal);
|
||||
break;
|
||||
}
|
||||
case GST_ITERATOR_RESYNC:
|
||||
case GST_ITERATOR_ERROR:
|
||||
case GST_ITERATOR_DONE:
|
||||
padDone = TRUE;
|
||||
break;
|
||||
};
|
||||
padId++;
|
||||
}
|
||||
|
||||
g_value_reset (&value);
|
||||
res.push_back(elementInfo);
|
||||
break;
|
||||
}
|
||||
case GST_ITERATOR_DONE:
|
||||
case GST_ITERATOR_RESYNC:
|
||||
case GST_ITERATOR_ERROR:
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gst_iterator_free (iter);
|
||||
|
||||
for(std::size_t i=0; i<res.size(); i++)
|
||||
{
|
||||
res[i].m_connections.resize(res[i].m_pads.size());
|
||||
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(m_pGraph), res[i].m_name.c_str());
|
||||
|
||||
for(std::size_t j=0; j<res[i].m_pads.size(); j++)
|
||||
{
|
||||
res[i].m_connections[j].m_elementId = -1;
|
||||
res[i].m_connections[j].m_padId = -1;
|
||||
|
||||
GstPad *pad = gst_element_get_static_pad (element, res[i].m_pads[j].m_name.c_str());
|
||||
GstPad *peerPad = gst_pad_get_peer(pad);
|
||||
|
||||
if(peerPad)
|
||||
{
|
||||
GstElement *peerElement = GST_ELEMENT(gst_pad_get_parent(peerPad));
|
||||
|
||||
gchar *peerName = gst_element_get_name(peerElement);
|
||||
gchar *peerPadName = gst_pad_get_name(peerPad);
|
||||
|
||||
for(std::size_t k=0; k<res.size(); k++)
|
||||
{
|
||||
if(res[k].m_name == peerName)
|
||||
{
|
||||
for(std::size_t l=0; l<res[k].m_pads.size(); l++)
|
||||
{
|
||||
if(res[k].m_pads[l].m_name == peerPadName)
|
||||
{
|
||||
res[i].m_connections[j].m_elementId = res[k].m_id;
|
||||
res[i].m_connections[j].m_padId = res[k].m_pads[l].m_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free(peerName);
|
||||
g_free(peerPadName);
|
||||
|
||||
gst_object_unref(peerPad);
|
||||
gst_object_unref(peerElement);
|
||||
}
|
||||
|
||||
gst_object_unref(pad);
|
||||
}
|
||||
gst_object_unref(element);
|
||||
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::Play()
|
||||
{
|
||||
GstStateChangeReturn res;
|
||||
gst_element_set_state(m_pGraph, GST_STATE_PLAYING);
|
||||
|
||||
GstState state;
|
||||
res = gst_element_get_state (m_pGraph, &state, NULL, GST_SECOND);
|
||||
|
||||
if(res != GST_STATE_CHANGE_SUCCESS)
|
||||
{
|
||||
gst_element_abort_state(m_pGraph);
|
||||
qDebug() << "state changing to Play was FAILED";
|
||||
}
|
||||
|
||||
return res == GST_STATE_PLAYING;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::Pause()
|
||||
{
|
||||
GstStateChangeReturn res;
|
||||
|
||||
GstState state;
|
||||
gst_element_set_state(m_pGraph, GST_STATE_PAUSED);
|
||||
res = gst_element_get_state (m_pGraph, &state, NULL, GST_SECOND);
|
||||
if(res != GST_STATE_CHANGE_SUCCESS)
|
||||
{
|
||||
gst_element_abort_state(m_pGraph);
|
||||
qDebug() << "state changing to Pause was FAILED";
|
||||
}
|
||||
|
||||
return res == GST_STATE_PAUSED;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::Stop()
|
||||
{
|
||||
GstStateChangeReturn res = gst_element_set_state(m_pGraph, GST_STATE_READY);
|
||||
return res == GST_STATE_CHANGE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
double GraphManager::GetPosition()
|
||||
{
|
||||
gint64 current, duration;
|
||||
if(!gst_element_query_position(m_pGraph, GST_FORMAT_TIME, ¤t))
|
||||
return 0;
|
||||
|
||||
if(!gst_element_query_duration(m_pGraph, GST_FORMAT_TIME, &duration))
|
||||
return 0;
|
||||
|
||||
if(duration < 0 || current < 0)
|
||||
return 0;
|
||||
|
||||
return (double) current / duration;
|
||||
}
|
||||
|
||||
|
||||
bool GraphManager::SetPosition(double pos)
|
||||
{
|
||||
GstQuery *query = gst_query_new_seeking(GST_FORMAT_TIME);
|
||||
if(!query)
|
||||
return false;
|
||||
|
||||
if(!gst_element_query(m_pGraph, query))
|
||||
return false;
|
||||
|
||||
gboolean seekable;
|
||||
gst_query_parse_seeking(query, NULL, &seekable, NULL, NULL);
|
||||
|
||||
gst_query_unref(query);
|
||||
|
||||
if(!seekable)
|
||||
return false;
|
||||
|
||||
gint64 duration;
|
||||
|
||||
if(!gst_element_query_duration(m_pGraph, GST_FORMAT_TIME, &duration))
|
||||
return 0;
|
||||
|
||||
if(duration < 0)
|
||||
return 0;
|
||||
|
||||
gboolean seekRes = gst_element_seek_simple(m_pGraph, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, duration * pos);
|
||||
|
||||
return seekRes;
|
||||
}
|
101
src/GraphManager.h
Normal file
101
src/GraphManager.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
#ifndef GRAPH_MANAGER_H_
|
||||
#define GRAPH_MANAGER_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct PadInfo
|
||||
{
|
||||
public:
|
||||
enum PadType
|
||||
{
|
||||
None,
|
||||
Out,
|
||||
In
|
||||
};
|
||||
|
||||
size_t m_id;
|
||||
PadType m_type;
|
||||
std::string m_name;
|
||||
|
||||
|
||||
bool operator == (const PadInfo &obj) const
|
||||
{
|
||||
if(this == &obj)
|
||||
return true;
|
||||
|
||||
if(m_id != obj.m_id)
|
||||
return false;
|
||||
|
||||
if(m_type != obj.m_type)
|
||||
return false;
|
||||
|
||||
if(m_name != obj.m_name)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ElementInfo
|
||||
{
|
||||
struct Connection
|
||||
{
|
||||
size_t m_padId;
|
||||
size_t m_elementId;
|
||||
|
||||
bool operator == (const Connection &obj) const
|
||||
{
|
||||
if(this == &obj)
|
||||
return true;
|
||||
|
||||
if(m_padId != obj.m_padId)
|
||||
return false;
|
||||
|
||||
if(m_elementId != obj.m_elementId)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
size_t m_id;
|
||||
std::string m_name;
|
||||
std::string m_pluginName;
|
||||
std::vector<PadInfo> m_pads;
|
||||
std::vector<Connection> m_connections;
|
||||
};
|
||||
|
||||
|
||||
class GraphManager
|
||||
{
|
||||
public:
|
||||
GraphManager();
|
||||
~GraphManager();
|
||||
|
||||
bool AddPlugin(const char *plugin, const char *name);
|
||||
bool RemovePlugin(const char *name);
|
||||
bool Connect(const char *srcElement, const char *srcPad,
|
||||
const char *dstElement, const char *dstPad);
|
||||
bool Disconnect(const char *srcElement, const char *srcPad,
|
||||
const char *dstElement, const char *dstPad);
|
||||
std::vector <ElementInfo> GetInfo();
|
||||
|
||||
bool OpenUri(const char *uri, const char *name);
|
||||
|
||||
double GetPosition();
|
||||
bool SetPosition(double);
|
||||
|
||||
|
||||
bool Play();
|
||||
bool Pause();
|
||||
bool Stop();
|
||||
|
||||
GstElement *m_pGraph;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
366
src/MainWindow.cpp
Normal file
366
src/MainWindow.cpp
Normal file
|
@ -0,0 +1,366 @@
|
|||
#include "MainWindow.h"
|
||||
|
||||
#include "PluginsList.h"
|
||||
|
||||
#include <QToolBar>
|
||||
#include <QAction>
|
||||
#include <QIcon>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QScopedArrayPointer>
|
||||
#include <QDebug>
|
||||
#include <QScrollArea>
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QPolygon>
|
||||
#include <QColor>
|
||||
#include <QMenuBar>
|
||||
#include <QMenu>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QSettings>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "GraphDisplay.h"
|
||||
#include "PipelineIE.h"
|
||||
#include "CustomSettings.h"
|
||||
#include "SeekSlider.h"
|
||||
|
||||
#include "version_info.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags):
|
||||
QMainWindow(parent, flags)
|
||||
,m_pGraph(new GraphManager)
|
||||
{
|
||||
QToolBar *ptb = addToolBar("Menu");
|
||||
|
||||
QAction *pactAdd = ptb -> addAction("Add...");
|
||||
pactAdd -> setShortcut(QKeySequence("Ctrl+F"));
|
||||
connect(pactAdd, SIGNAL(triggered()), SLOT(AddPlugin()));
|
||||
|
||||
|
||||
QAction *pactOpenFile = ptb -> addAction("Open File...");
|
||||
connect(pactOpenFile, SIGNAL(triggered()), SLOT(OpenFile()));
|
||||
|
||||
ptb -> addSeparator();
|
||||
|
||||
QPixmap pxPlay(24, 24);
|
||||
pxPlay.fill(QColor(0, 0, 0, 0));
|
||||
QPainter pntrPlay(&pxPlay);
|
||||
pntrPlay.setPen(Qt::darkGreen);
|
||||
pntrPlay.setBrush(QBrush(Qt::darkGreen));
|
||||
|
||||
QPolygon polygon(3);
|
||||
polygon.setPoint(0, 4, 4);
|
||||
polygon.setPoint(1, 4, 20);
|
||||
polygon.setPoint(2, 20, 12);
|
||||
|
||||
pntrPlay.drawPolygon(polygon, Qt::WindingFill);
|
||||
|
||||
QAction *pactPlay = ptb -> addAction(QIcon(pxPlay), "Play");
|
||||
connect(pactPlay, SIGNAL(triggered()), SLOT(Play()));
|
||||
|
||||
QPixmap pxPause(24, 24);
|
||||
pxPause.fill(QColor(0, 0, 0, 0));
|
||||
QPainter pntrPause(&pxPause);
|
||||
pntrPause.setPen(Qt::darkGray);
|
||||
pntrPause.setBrush(QBrush(Qt::darkGray));
|
||||
|
||||
pntrPause.drawRect(8, 4, 3, 16);
|
||||
pntrPause.drawRect(13, 4, 3, 16);
|
||||
|
||||
QAction *pactPause = ptb -> addAction(QIcon(pxPause), "Pause");
|
||||
connect(pactPause, SIGNAL(triggered()), SLOT(Pause()));
|
||||
|
||||
QPixmap pxStop(24, 24);
|
||||
pxStop.fill(QColor(0, 0, 0, 0));
|
||||
QPainter pntrStop(&pxStop);
|
||||
pntrStop.setPen(Qt::darkRed);
|
||||
pntrStop.setBrush(QBrush(Qt::darkRed));
|
||||
|
||||
pntrStop.drawRect(6, 6, 12, 12);
|
||||
|
||||
QAction *pactStop = ptb -> addAction(QIcon(pxStop), "Stop");
|
||||
connect(pactStop, SIGNAL(triggered()), SLOT(Stop()));
|
||||
|
||||
QPixmap pxFulsh(24, 24);
|
||||
pxFulsh.fill(QColor(0, 0, 0, 0));
|
||||
QPainter pntrFlush(&pxFulsh);
|
||||
pntrFlush.setPen(Qt::darkGreen);
|
||||
pntrFlush.setBrush(QBrush(Qt::darkGreen));
|
||||
|
||||
pntrFlush.drawRect(3, 4, 3, 16);
|
||||
|
||||
polygon = QPolygon(3);
|
||||
polygon.setPoint(0, 9, 4);
|
||||
polygon.setPoint(1, 9, 20);
|
||||
polygon.setPoint(2, 21, 12);
|
||||
|
||||
pntrFlush.drawPolygon(polygon, Qt::WindingFill);
|
||||
|
||||
QAction *pactFlush = ptb -> addAction(QIcon(pxFulsh), "Flush");
|
||||
connect(pactFlush, SIGNAL(triggered()), SLOT(Flush()));
|
||||
|
||||
|
||||
ptb -> addSeparator();
|
||||
|
||||
m_pslider = new SeekSlider();
|
||||
m_pslider -> setOrientation(Qt::Horizontal);
|
||||
m_pslider -> setRange(0, 10000);
|
||||
m_pslider -> setTracking(false);
|
||||
|
||||
connect(m_pslider, SIGNAL(valueChanged(int)), SLOT(Seek(int)));
|
||||
ptb -> addWidget(m_pslider);
|
||||
|
||||
QMenu *pmenu = menuBar() -> addMenu("&File");
|
||||
|
||||
QAction *pactOpen = pmenu -> addAction ("Open...", this, SLOT(Open()), QKeySequence::Open);
|
||||
addAction (pactOpen);
|
||||
|
||||
QAction *pactSave = pmenu -> addAction ("Save", this, SLOT(Save()), QKeySequence::Save);
|
||||
addAction (pactSave);
|
||||
|
||||
QAction *pactSaveAs = pmenu -> addAction ("Save As...", this, SLOT(SaveAs()), QKeySequence::SaveAs);
|
||||
addAction (pactSaveAs);
|
||||
|
||||
pmenu -> addSeparator();
|
||||
pmenu -> addAction("Exit", this, SLOT(close()));
|
||||
|
||||
|
||||
pmenu = menuBar() -> addMenu("&Graph");
|
||||
|
||||
pmenu -> addAction(pactAdd);
|
||||
pmenu -> addAction(pactOpenFile);
|
||||
pmenu -> addAction ("Open Uri...", this, SLOT(OpenUri()));
|
||||
pmenu -> addSeparator();
|
||||
pmenu -> addAction(pactPlay);
|
||||
pmenu -> addAction(pactPause);
|
||||
pmenu -> addAction(pactStop);
|
||||
pmenu -> addAction(pactFlush);
|
||||
|
||||
|
||||
pmenu = menuBar() -> addMenu("&Help");
|
||||
|
||||
pmenu -> addAction ("About pipeviz...", this, SLOT(About()));
|
||||
|
||||
|
||||
m_pGraphDisplay = new GraphDisplay;
|
||||
|
||||
QScrollArea *pscroll = new QScrollArea;
|
||||
pscroll -> setWidget(m_pGraphDisplay);
|
||||
pscroll -> setWidgetResizable(false);
|
||||
m_pGraphDisplay -> resize(10000, 10000);
|
||||
m_pGraphDisplay -> m_pGraph = m_pGraph;
|
||||
setCentralWidget(pscroll);
|
||||
m_pstatusBar = new QStatusBar;
|
||||
setStatusBar(m_pstatusBar);
|
||||
|
||||
restoreGeometry(CustomSettings::mainWindowGeometry());
|
||||
|
||||
startTimer(100);
|
||||
}
|
||||
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
CustomSettings::saveMainWindowGeometry(saveGeometry());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::AddPlugin()
|
||||
{
|
||||
PluginsList lst(this);
|
||||
lst.m_pGraph = m_pGraph.data();
|
||||
|
||||
lst.exec();
|
||||
std::vector<ElementInfo> info = m_pGraph -> GetInfo();
|
||||
m_pGraphDisplay -> update(info);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MainWindow::OpenFile()
|
||||
{
|
||||
QString dir = CustomSettings::lastIODirectory();
|
||||
|
||||
QString path = QFileDialog::getOpenFileName(this, "Open File...", dir );
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
gchar *uri = gst_filename_to_uri(path.toStdString().c_str(), NULL);
|
||||
if(uri)
|
||||
{
|
||||
qDebug() << "Open Source file: " << path;
|
||||
|
||||
m_pGraph -> OpenUri(uri, NULL);
|
||||
g_free(uri);
|
||||
|
||||
std::vector<ElementInfo> info = m_pGraph -> GetInfo();
|
||||
m_pGraphDisplay -> update(info);
|
||||
|
||||
QString dir = QFileInfo(path).absoluteDir().absolutePath();
|
||||
CustomSettings::saveLastIODirectory(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::OpenUri()
|
||||
{
|
||||
QString uri = QInputDialog::getText(this, "Open Uri...", "Uri:");
|
||||
|
||||
if(!uri.isEmpty())
|
||||
{
|
||||
qDebug() << "Open uri: " << uri;
|
||||
m_pGraph -> OpenUri(uri.toStdString().c_str(), NULL);
|
||||
|
||||
std::vector<ElementInfo> info = m_pGraph -> GetInfo();
|
||||
m_pGraphDisplay -> update(info);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Play()
|
||||
{
|
||||
qDebug() << "Play";
|
||||
m_pGraph -> Play();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Pause()
|
||||
{
|
||||
qDebug() << "Pause";
|
||||
m_pGraph -> Pause();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Stop()
|
||||
{
|
||||
qDebug() << "Stop";
|
||||
m_pGraph -> Stop();
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Flush()
|
||||
{
|
||||
qDebug() << "Flush";
|
||||
|
||||
if(m_pGraph -> m_pGraph)
|
||||
{
|
||||
gst_element_send_event(GST_ELEMENT(m_pGraph -> m_pGraph), gst_event_new_flush_start());
|
||||
gst_element_send_event(GST_ELEMENT(m_pGraph -> m_pGraph), gst_event_new_flush_stop(true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Seek(int val)
|
||||
{
|
||||
if(m_pGraph -> SetPosition((double)(val) / m_pslider -> maximum()))
|
||||
qDebug() << "Seek to" << val;
|
||||
else
|
||||
qDebug() << "Seek to" << val << "was FAILED";
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::timerEvent(QTimerEvent *)
|
||||
{
|
||||
GstState state;
|
||||
GstStateChangeReturn res = gst_element_get_state (m_pGraph -> m_pGraph, &state, NULL, GST_MSECOND);
|
||||
|
||||
if(res == GST_STATE_CHANGE_SUCCESS)
|
||||
{
|
||||
QString str;
|
||||
switch(state)
|
||||
{
|
||||
case GST_STATE_VOID_PENDING:
|
||||
str = "Pending";
|
||||
break;
|
||||
case GST_STATE_NULL:
|
||||
str = "Null";
|
||||
break;
|
||||
case GST_STATE_READY:
|
||||
str = "Ready";
|
||||
break;
|
||||
case GST_STATE_PAUSED:
|
||||
str = "Paused";
|
||||
break;
|
||||
case GST_STATE_PLAYING:
|
||||
str = "Playing";
|
||||
break;
|
||||
};
|
||||
|
||||
m_pstatusBar -> showMessage(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pstatusBar -> showMessage(QString(gst_element_state_change_return_get_name(res)));
|
||||
}
|
||||
|
||||
double pos = m_pGraph -> GetPosition();
|
||||
|
||||
if(m_pslider -> value() != (int)(m_pslider -> maximum() * pos))
|
||||
m_pslider -> setSliderPosition(m_pslider -> maximum() * pos);
|
||||
|
||||
|
||||
m_pGraphDisplay -> update(m_pGraph -> GetInfo());
|
||||
}
|
||||
|
||||
|
||||
|
||||
void MainWindow::Save()
|
||||
{
|
||||
if(m_fileName.isEmpty())
|
||||
SaveAs();
|
||||
else
|
||||
PipelineIE::Export(m_pGraph, m_fileName);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::SaveAs()
|
||||
{
|
||||
QString dir = CustomSettings::lastIODirectory();
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(this, "Save As...", dir);
|
||||
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
m_fileName = path;
|
||||
Save();
|
||||
|
||||
QString dir = QFileInfo(path).absoluteDir().absolutePath();
|
||||
CustomSettings::saveLastIODirectory(dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::Open()
|
||||
{
|
||||
QString dir = CustomSettings::lastIODirectory();
|
||||
|
||||
QString path = QFileDialog::getOpenFileName(this, "Open...", dir);
|
||||
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
if(PipelineIE::Import(m_pGraph, path))
|
||||
m_fileName = path;
|
||||
|
||||
QString dir = QFileInfo(path).absoluteDir().absolutePath();
|
||||
CustomSettings::saveLastIODirectory(dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::About()
|
||||
{
|
||||
QString message;
|
||||
message = "<center><b>pipeviz</b></center><br>";
|
||||
message = "<center>virinext@gmail.com</center><br>";
|
||||
message += QString("<center>Version: ") + VERSION_STR + "</center><br>";
|
||||
message += "<center>GUI Based on Qt</center>";
|
||||
QMessageBox::about(this, "About", message);
|
||||
}
|
56
src/MainWindow.h
Normal file
56
src/MainWindow.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef MAIN_WINDOW_H_
|
||||
#define MAIN_WINDOW_H_
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QSharedPointer>
|
||||
#include <QStatusBar>
|
||||
#include <QAction>
|
||||
#include <QSlider>
|
||||
|
||||
#include <gst/gstbuffer.h>
|
||||
#include <gst/gstevent.h>
|
||||
#include <gst/gstcaps.h>
|
||||
|
||||
#include "GraphManager.h"
|
||||
|
||||
class GraphDisplay;
|
||||
|
||||
class MainWindow: public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *);
|
||||
|
||||
private slots:
|
||||
void AddPlugin();
|
||||
void OpenFile();
|
||||
void OpenUri();
|
||||
void Play();
|
||||
void Pause();
|
||||
void Stop();
|
||||
void Flush();
|
||||
void Seek(int);
|
||||
|
||||
void Save();
|
||||
void SaveAs();
|
||||
void Open();
|
||||
|
||||
void About();
|
||||
|
||||
private:
|
||||
QSharedPointer<GraphManager> m_pGraph;
|
||||
GraphDisplay *m_pGraphDisplay;
|
||||
|
||||
QStatusBar *m_pstatusBar;
|
||||
QSlider *m_pslider;
|
||||
|
||||
QString m_fileName;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
95
src/PadProperties.cpp
Normal file
95
src/PadProperties.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include "PadProperties.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QDebug>
|
||||
#include <QScrollArea>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
PadProperties::PadProperties(QSharedPointer<GraphManager> pGraphManager, const char *elementName, const char *padName,
|
||||
QWidget *parent, Qt::WindowFlags flags):
|
||||
QWidget(parent, flags)
|
||||
{
|
||||
setWindowTitle(QString(elementName) + "::" + padName + " properties");
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(pGraphManager -> m_pGraph), elementName);
|
||||
|
||||
if(!element)
|
||||
return;
|
||||
|
||||
GstPad *pad = gst_element_get_static_pad(GST_ELEMENT(element), padName);
|
||||
|
||||
QGridLayout *play = new QGridLayout;
|
||||
|
||||
play -> addWidget(new QLabel("Name"), 0, 0);
|
||||
|
||||
QLabel *plbl = new QLabel(padName);
|
||||
plbl -> setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
play -> addWidget(plbl, 0, 1);
|
||||
|
||||
play -> addWidget(new QLabel("All caps:"), 1, 0);
|
||||
GstCaps *caps = gst_pad_query_caps(pad, NULL);
|
||||
gchar *str;
|
||||
gchar *noSpecified = (gchar *)"not specified";
|
||||
if(caps)
|
||||
str = gst_caps_to_string(caps);
|
||||
else
|
||||
str = noSpecified;
|
||||
|
||||
plbl = new QLabel(QString(str));
|
||||
plbl -> setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
play -> addWidget(plbl, 1, 1);
|
||||
if(caps)
|
||||
{
|
||||
g_free(str);
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
|
||||
play -> addWidget(new QLabel("Allowed caps:"), 2, 0);
|
||||
caps = gst_pad_get_allowed_caps(pad);
|
||||
str = NULL;
|
||||
if(caps)
|
||||
str = gst_caps_to_string(caps);
|
||||
else
|
||||
str = noSpecified;
|
||||
|
||||
plbl = new QLabel(QString(str));
|
||||
plbl -> setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
play -> addWidget(plbl, 2, 1);
|
||||
if(caps)
|
||||
{
|
||||
g_free(str);
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
|
||||
play -> addWidget(new QLabel("Current caps"), 3, 0);
|
||||
caps = gst_pad_get_current_caps(pad);
|
||||
str = NULL;
|
||||
if(caps)
|
||||
str = gst_caps_to_string(caps);
|
||||
else
|
||||
str = noSpecified;
|
||||
|
||||
plbl = new QLabel(QString(str));
|
||||
plbl -> setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
|
||||
play -> addWidget(plbl, 3, 1);
|
||||
if(caps)
|
||||
{
|
||||
g_free(str);
|
||||
gst_caps_unref(caps);
|
||||
}
|
||||
|
||||
gst_object_unref(element);
|
||||
gst_object_unref (pad);
|
||||
|
||||
QVBoxLayout *pvblay = new QVBoxLayout;
|
||||
QWidget *pwgt = new QWidget(this);
|
||||
pwgt -> setLayout(play);
|
||||
QScrollArea *pscroll = new QScrollArea(this);
|
||||
pscroll -> setWidget(pwgt);
|
||||
|
||||
pvblay -> addWidget(pscroll);
|
||||
|
||||
setLayout(pvblay);
|
||||
}
|
17
src/PadProperties.h
Normal file
17
src/PadProperties.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef PAD_PROPERTIES_H_
|
||||
#define PAD_PROPERTIES_H_
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "GraphManager.h"
|
||||
|
||||
class PadProperties: public QWidget
|
||||
{
|
||||
public:
|
||||
PadProperties(QSharedPointer<GraphManager> pGraphManager, const char *element, const char *pad
|
||||
, QWidget *parent = 0, Qt::WindowFlags flags = 0);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
610
src/PipelineIE.cpp
Normal file
610
src/PipelineIE.cpp
Normal file
|
@ -0,0 +1,610 @@
|
|||
#include "PipelineIE.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QMessageBox>
|
||||
#include <QDomDocument>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
static void clearPipeline(GstElement *pipeline)
|
||||
{
|
||||
if(!pipeline)
|
||||
return;
|
||||
|
||||
GstIterator *iter;
|
||||
iter = gst_bin_iterate_elements (GST_BIN (pipeline));
|
||||
|
||||
bool done = false;
|
||||
while (!done)
|
||||
{
|
||||
GValue value = { 0 };
|
||||
switch (gst_iterator_next (iter, &value))
|
||||
{
|
||||
case GST_ITERATOR_OK:
|
||||
{
|
||||
GstElement *element = GST_ELEMENT(g_value_get_object(&value));
|
||||
gst_bin_remove(GST_BIN(pipeline), element);
|
||||
g_value_reset (&value);
|
||||
|
||||
iter = gst_bin_iterate_elements (GST_BIN (pipeline));
|
||||
if(!iter)
|
||||
done = true;
|
||||
|
||||
break;
|
||||
}
|
||||
case GST_ITERATOR_DONE:
|
||||
case GST_ITERATOR_RESYNC:
|
||||
case GST_ITERATOR_ERROR:
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gst_iterator_free (iter);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Connection
|
||||
{
|
||||
std::string element1;
|
||||
std::string pad1;
|
||||
std::string element2;
|
||||
std::string pad2;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static void writeProperties(QXmlStreamWriter &xmlWriter, const GstElement *element)
|
||||
{
|
||||
GParamSpec **prop_specs;
|
||||
guint num_props;
|
||||
|
||||
prop_specs = g_object_class_list_properties(G_OBJECT_GET_CLASS (element),
|
||||
&num_props);
|
||||
|
||||
if(!num_props)
|
||||
return;
|
||||
|
||||
xmlWriter.writeStartElement("properties");
|
||||
|
||||
for(std::size_t i = 0; i<num_props; i++)
|
||||
{
|
||||
GParamSpec *param = prop_specs[i];
|
||||
|
||||
if((param -> flags & G_PARAM_READABLE) && (param -> flags & G_PARAM_WRITABLE))
|
||||
{
|
||||
GValue value = { 0 };
|
||||
g_value_init (&value, param -> value_type);
|
||||
|
||||
g_object_get_property (G_OBJECT(element), param -> name, &value);
|
||||
|
||||
if(!g_param_value_defaults(param, &value))
|
||||
{
|
||||
bool skip = false;
|
||||
QString propertyName = g_param_spec_get_name (param);
|
||||
QString propertyValue;
|
||||
|
||||
|
||||
switch (G_VALUE_TYPE (&value))
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
{
|
||||
|
||||
const char *string_val = g_value_get_string (&value);
|
||||
if(string_val)
|
||||
propertyValue = string_val;
|
||||
else
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
case G_TYPE_BOOLEAN:
|
||||
{
|
||||
gboolean bool_val = g_value_get_boolean (&value);
|
||||
propertyValue = QString::number(bool_val);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_ULONG:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_ulong(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_LONG:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_long(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_uint(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_int(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT64:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_uint64(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT64:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_int64(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_FLOAT:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_float(&value));
|
||||
break;
|
||||
}
|
||||
case G_TYPE_DOUBLE:
|
||||
{
|
||||
propertyValue = QString::number(g_value_get_double(&value));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
gchar *elementName = gst_element_get_name(element);
|
||||
|
||||
qDebug() << "property `" << propertyName << "` for `"
|
||||
<< elementName << "` not supported";
|
||||
g_free(elementName);
|
||||
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if(!skip)
|
||||
{
|
||||
xmlWriter.writeStartElement("property");
|
||||
xmlWriter.writeAttribute("name", propertyName);
|
||||
xmlWriter.writeAttribute("value", propertyValue);
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
g_value_reset(&value);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
|
||||
g_free(prop_specs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void loadProperties(QDomElement node, GstElement *element)
|
||||
{
|
||||
QDomNode child = node.firstChild();
|
||||
while(!child.isNull())
|
||||
{
|
||||
if(child.toElement().tagName() == "property")
|
||||
{
|
||||
QString name = child.toElement().attribute("name");
|
||||
QString value = child.toElement().attribute("value");
|
||||
|
||||
GParamSpec *param = g_object_class_find_property(G_OBJECT_GET_CLASS (element),
|
||||
name.toStdString().c_str());
|
||||
|
||||
if(!param)
|
||||
{
|
||||
gchar *elementName = gst_element_get_name(element);
|
||||
qDebug() << "problem with setting property `" << name << "` for `" << elementName << "`";
|
||||
g_free(elementName);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!(param -> flags & G_PARAM_WRITABLE))
|
||||
continue;
|
||||
|
||||
std::string tmpStr = name.toStdString();
|
||||
const char *propName = tmpStr.c_str();
|
||||
switch (param -> value_type)
|
||||
{
|
||||
case G_TYPE_STRING:
|
||||
{
|
||||
g_object_set(G_OBJECT(element), propName, value.toStdString().c_str(), NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_BOOLEAN:
|
||||
{
|
||||
gboolean val = value.toInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_ULONG:
|
||||
{
|
||||
gulong val = value.toULong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_LONG:
|
||||
{
|
||||
glong val = value.toLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT:
|
||||
{
|
||||
guint val = value.toUInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT:
|
||||
{
|
||||
gint val = value.toInt();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_UINT64:
|
||||
{
|
||||
guint64 val = value.toULongLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_INT64:
|
||||
{
|
||||
gint64 val = value.toLongLong();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_FLOAT:
|
||||
{
|
||||
gfloat val = value.toFloat();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
case G_TYPE_DOUBLE:
|
||||
{
|
||||
gdouble val = value.toDouble();
|
||||
g_object_set(G_OBJECT(element), propName, val, NULL);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
gchar *elementName = gst_element_get_name(element);
|
||||
qDebug() << "property `" << name << "` for `" << QString(elementName) << "` not supported";
|
||||
g_free(elementName);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
child = child.nextSibling();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void create_requst_pad(GstElement *element, const QString &templateName, const QString &padName)
|
||||
{
|
||||
GstElementClass *klass = GST_ELEMENT_GET_CLASS(element);
|
||||
|
||||
GstPadTemplate *templ = gst_element_class_get_pad_template(klass, templateName.toStdString().c_str());
|
||||
|
||||
gst_element_request_pad(element, templ, padName.toStdString().c_str(), NULL);
|
||||
}
|
||||
|
||||
bool PipelineIE::Export(QSharedPointer<GraphManager> pgraph, const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
{
|
||||
QMessageBox::warning(0, "Read only", "The file is in read only mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector <ElementInfo> info = pgraph -> GetInfo();
|
||||
|
||||
QXmlStreamWriter xmlWriter;
|
||||
xmlWriter.setDevice(&file);
|
||||
xmlWriter.writeStartDocument();
|
||||
xmlWriter.writeStartElement("pipeline");
|
||||
|
||||
for(std::size_t i=0; i<info.size(); i++)
|
||||
{
|
||||
xmlWriter.writeStartElement("element");
|
||||
|
||||
xmlWriter.writeAttribute("name", info[i].m_name.c_str());
|
||||
xmlWriter.writeAttribute("plugin-name", info[i].m_pluginName.c_str());
|
||||
|
||||
GstElement *element = gst_bin_get_by_name (GST_BIN(pgraph -> m_pGraph), info[i].m_name.c_str());
|
||||
|
||||
for(std::size_t j=0; j<info[i].m_pads.size(); j++)
|
||||
{
|
||||
xmlWriter.writeStartElement("pad");
|
||||
|
||||
xmlWriter.writeAttribute("name", info[i].m_pads[j].m_name.c_str());
|
||||
|
||||
GstPad *pad = gst_element_get_static_pad(element, info[i].m_pads[j].m_name.c_str());
|
||||
|
||||
GstPadTemplate *templ = gst_pad_get_pad_template(pad);
|
||||
|
||||
QString presence;
|
||||
switch(GST_PAD_TEMPLATE_PRESENCE(templ))
|
||||
{
|
||||
case GST_PAD_ALWAYS:
|
||||
presence = "always";
|
||||
break;
|
||||
|
||||
case GST_PAD_SOMETIMES:
|
||||
presence = "sometimes";
|
||||
break;
|
||||
|
||||
case GST_PAD_REQUEST:
|
||||
presence = "request";
|
||||
break;
|
||||
};
|
||||
|
||||
xmlWriter.writeAttribute("presence", presence);
|
||||
xmlWriter.writeAttribute("template-name", GST_PAD_TEMPLATE_NAME_TEMPLATE(templ));
|
||||
|
||||
gst_object_unref(pad);
|
||||
|
||||
if(info[i].m_connections[j].m_elementId != (size_t)-1 &&
|
||||
info[i].m_connections[j].m_padId != (size_t)-1)
|
||||
{
|
||||
std::size_t elementPos, padPos;
|
||||
for(elementPos = 0; elementPos < info.size(); elementPos++)
|
||||
{
|
||||
if(info[elementPos].m_id == info[i].m_connections[j].m_elementId)
|
||||
{
|
||||
for(padPos = 0; padPos < info[elementPos].m_pads.size(); padPos++)
|
||||
if(info[elementPos].m_pads[padPos].m_id == info[i].m_connections[j].m_padId)
|
||||
break;
|
||||
|
||||
if(padPos < info[elementPos].m_pads.size())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(elementPos < info.size() && padPos < info[elementPos].m_pads.size())
|
||||
{
|
||||
xmlWriter.writeStartElement("connected-to");
|
||||
xmlWriter.writeAttribute("element-name", info[elementPos].m_name.c_str());
|
||||
xmlWriter.writeAttribute("pad-name", info[elementPos].m_pads[padPos].m_name.c_str());
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
writeProperties(xmlWriter, element);
|
||||
gst_object_unref(element);
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
}
|
||||
|
||||
xmlWriter.writeEndElement();
|
||||
xmlWriter.writeEndDocument();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PipelineIE::Import(QSharedPointer<GraphManager> pgraph, const QString &fileName)
|
||||
{
|
||||
GstElement *pipeline = pgraph -> m_pGraph;
|
||||
QFile file(fileName);
|
||||
if(!file.open(QFile::ReadOnly | QFile::Text))
|
||||
{
|
||||
QMessageBox::warning(0, "Open failed",
|
||||
QString("Cannot read file ") + fileName +
|
||||
": " + file.errorString());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString errorStr;
|
||||
int errorLine;
|
||||
int errorColumn;
|
||||
|
||||
QDomDocument doc;
|
||||
if(!doc.setContent(&file, false, &errorStr, &errorLine, &errorColumn))
|
||||
{
|
||||
QMessageBox::warning(0, "Xml parsing failed",
|
||||
QString("Parse error at line ") + QString::number(errorLine) + ", "
|
||||
"column " + QString::number(errorColumn) + ": " + errorStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
clearPipeline(pipeline);
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
|
||||
if(root.tagName() != "pipeline")
|
||||
{
|
||||
QMessageBox::warning(0, "Parsing failed", "Is invalid pipeline file");
|
||||
return false;
|
||||
}
|
||||
|
||||
QDomNode child = root.firstChild();
|
||||
|
||||
std::vector<Connection> connections;
|
||||
while(!child.isNull())
|
||||
{
|
||||
if(child.toElement().tagName() == "element")
|
||||
{
|
||||
QDomElement elNode = child.toElement();
|
||||
|
||||
|
||||
GstElement *pel = gst_element_factory_make(elNode.attribute("plugin-name").toStdString().c_str(),
|
||||
elNode.attribute("name").toStdString().c_str());
|
||||
|
||||
if(!pel)
|
||||
{
|
||||
QMessageBox::warning(0, "Element creation failed",
|
||||
QString("Could not create element of `") +
|
||||
elNode.attribute("plugin-name") + "` with name `" +
|
||||
elNode.attribute("name") + "`");
|
||||
|
||||
child = child.nextSibling();
|
||||
continue;
|
||||
}
|
||||
|
||||
bool res = gst_bin_add(GST_BIN(pipeline), pel);
|
||||
|
||||
if(!res)
|
||||
{
|
||||
QMessageBox::warning(0, "Element insertion failed",
|
||||
QString("Could not insert element `") +
|
||||
elNode.attribute("name") + "` to pipeline");
|
||||
|
||||
child = child.nextSibling();
|
||||
continue;
|
||||
}
|
||||
|
||||
gst_element_sync_state_with_parent(pel);
|
||||
|
||||
|
||||
QDomNode elementChild = elNode.firstChild();
|
||||
while(!elementChild.isNull())
|
||||
{
|
||||
if(elementChild.toElement().tagName() == "pad")
|
||||
{
|
||||
QDomNode padChild = elementChild.firstChild();
|
||||
QDomElement elPad = elementChild.toElement();
|
||||
// GstPadPresence presence = GST_PAD_ALWAYS;
|
||||
|
||||
QString templaneName;
|
||||
if(elPad.attribute("presence") == "request")
|
||||
create_requst_pad(pel, elPad.attribute("template-name"), elPad.attribute("name"));
|
||||
|
||||
while(!padChild.isNull())
|
||||
{
|
||||
if(padChild.toElement().tagName() == "connected-to")
|
||||
{
|
||||
bool isExists = false;
|
||||
QDomElement elCoonnectedTo = padChild.toElement();
|
||||
|
||||
for(std::size_t i=0; i<connections.size(); i++)
|
||||
{
|
||||
if((connections[i].element1 == elNode.attribute("name").toStdString() &&
|
||||
connections[i].element2 == elCoonnectedTo.attribute("element-name").toStdString() &&
|
||||
connections[i].pad1 == elPad.attribute("name").toStdString() &&
|
||||
connections[i].pad2 == elCoonnectedTo.attribute("pad-name").toStdString())
|
||||
||
|
||||
(connections[i].element2 == elNode.attribute("name").toStdString() &&
|
||||
connections[i].element1 == elCoonnectedTo.attribute("element-name").toStdString() &&
|
||||
connections[i].pad2 == elPad.attribute("name").toStdString() &&
|
||||
connections[i].pad1 ==elCoonnectedTo.attribute("pad-name").toStdString())
|
||||
)
|
||||
{
|
||||
isExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isExists)
|
||||
{
|
||||
Connection newConnetion;
|
||||
newConnetion.element1 = elNode.attribute("name").toStdString();
|
||||
newConnetion.element2 = padChild.toElement().attribute("element-name").toStdString();
|
||||
newConnetion.pad1 = elementChild.toElement().attribute("name").toStdString();
|
||||
newConnetion.pad2 = padChild.toElement().attribute("pad-name").toStdString();
|
||||
|
||||
connections.push_back(newConnetion);
|
||||
}
|
||||
}
|
||||
padChild = padChild.nextSibling();
|
||||
}
|
||||
}
|
||||
else if(elementChild.toElement().tagName() == "properties")
|
||||
{
|
||||
loadProperties(elementChild.toElement(), pel);
|
||||
}
|
||||
elementChild = elementChild.nextSibling();
|
||||
}
|
||||
}
|
||||
child = child.nextSibling();
|
||||
}
|
||||
|
||||
std::size_t maxStarts = 5;
|
||||
bool setReady = true;
|
||||
for(std::size_t k=0; k<maxStarts; k++)
|
||||
{
|
||||
if(connections.empty())
|
||||
break;
|
||||
|
||||
if(k > 0)
|
||||
setReady = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
std::size_t i=0;
|
||||
for(; i<connections.size(); i++)
|
||||
{
|
||||
GstElement *el1 = gst_bin_get_by_name (GST_BIN(pipeline), connections[i].element1.c_str());
|
||||
GstElement *el2 = gst_bin_get_by_name (GST_BIN(pipeline), connections[i].element2.c_str());
|
||||
|
||||
if(!el1 || !el2)
|
||||
{
|
||||
QMessageBox::warning(0, "Internal error",
|
||||
QString("Could not find one of elements `") +
|
||||
QString(connections[i].element1.c_str()) + "`, `" +
|
||||
QString(connections[i].element2.c_str()) + "`");
|
||||
|
||||
gst_object_unref(el1);
|
||||
gst_object_unref(el2);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
GstPad *pad1 = gst_element_get_static_pad(el1, connections[i].pad1.c_str());
|
||||
GstPad *pad2 = gst_element_get_static_pad(el2, connections[i].pad2.c_str());
|
||||
|
||||
if(pad1 && pad2)
|
||||
{
|
||||
if(GST_PAD_IS_SRC(pad1))
|
||||
gst_element_link_pads(el1, connections[i].pad1.c_str(), el2, connections[i].pad2.c_str());
|
||||
else
|
||||
gst_element_link_pads(el2, connections[i].pad2.c_str(), el1, connections[i].pad1.c_str());
|
||||
|
||||
gst_object_unref(pad1);
|
||||
gst_object_unref(pad2);
|
||||
connections.erase(connections.begin() + i);
|
||||
|
||||
gst_object_unref(el1);
|
||||
gst_object_unref(el2);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if(pad1)
|
||||
gst_object_unref(pad1);
|
||||
|
||||
if(pad2)
|
||||
gst_object_unref(pad2);
|
||||
|
||||
gst_object_unref(el1);
|
||||
gst_object_unref(el2);
|
||||
}
|
||||
|
||||
if(i == connections.size())
|
||||
break;
|
||||
}
|
||||
|
||||
if(!connections.empty())
|
||||
{
|
||||
gst_element_set_state(pipeline, GST_STATE_PAUSED);
|
||||
|
||||
GstState state;
|
||||
gst_element_get_state (pipeline, &state, NULL, GST_MSECOND * 2500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(setReady)
|
||||
gst_element_set_state(pipeline, GST_STATE_READY);
|
||||
|
||||
return true;
|
||||
}
|
15
src/PipelineIE.h
Normal file
15
src/PipelineIE.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef PIPELINE_IMPORT_EXPORT_H_
|
||||
#define PIPELINE_IMPORT_EXPORT_H_
|
||||
|
||||
#include <QString>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "GraphManager.h"
|
||||
|
||||
namespace PipelineIE
|
||||
{
|
||||
bool Export(QSharedPointer<GraphManager> pgraph, const QString &fileName);
|
||||
bool Import(QSharedPointer<GraphManager> pgraph, const QString &fileName);
|
||||
};
|
||||
|
||||
#endif
|
209
src/PluginsList.cpp
Normal file
209
src/PluginsList.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
#include "PluginsList.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QScrollArea>
|
||||
#include <QMessageBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace
|
||||
{
|
||||
void InitPluginsList(QListWidget *plwgt)
|
||||
{
|
||||
std::size_t num = 0;
|
||||
GList *plugins;
|
||||
plugins = gst_registry_get_plugin_list(gst_registry_get());
|
||||
while(plugins)
|
||||
{
|
||||
GstPlugin *plugin;
|
||||
plugin = (GstPlugin *) (plugins->data);
|
||||
plugins = g_list_next (plugins);
|
||||
|
||||
GList *features = gst_registry_get_feature_list_by_plugin (gst_registry_get (),
|
||||
gst_plugin_get_name (plugin));
|
||||
|
||||
while(features)
|
||||
{
|
||||
GstPluginFeature *feature;
|
||||
feature = GST_PLUGIN_FEATURE (features->data);
|
||||
if(GST_IS_ELEMENT_FACTORY (feature))
|
||||
{
|
||||
GstElementFactory *factory;
|
||||
factory = GST_ELEMENT_FACTORY (feature);
|
||||
plwgt -> addItem(GST_OBJECT_NAME (factory));
|
||||
num++;
|
||||
}
|
||||
|
||||
features = g_list_next (features);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PluginsList::PluginsList(QWidget *pwgt, Qt::WindowFlags f):
|
||||
QDialog(pwgt, f)
|
||||
,m_pGraph(NULL)
|
||||
{
|
||||
m_pPlugins = new QListWidget;
|
||||
m_plblInfo = new QLabel;
|
||||
|
||||
m_plblInfo -> setTextInteractionFlags(Qt::TextSelectableByMouse);
|
||||
m_plblInfo -> setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
QScrollArea *pscroll = new QScrollArea;
|
||||
pscroll -> setWidget(m_plblInfo);
|
||||
m_plblInfo -> resize(pscroll -> size());
|
||||
|
||||
QHBoxLayout *phblay = new QHBoxLayout;
|
||||
|
||||
phblay -> addWidget(m_pPlugins, 1);
|
||||
phblay -> addWidget(pscroll, 2);
|
||||
|
||||
InitPluginsList(m_pPlugins);
|
||||
|
||||
QHBoxLayout *phblayFind = new QHBoxLayout;
|
||||
|
||||
QLineEdit *ple = new QLineEdit;
|
||||
phblayFind -> addWidget(ple);
|
||||
phblayFind -> addStretch(1);
|
||||
|
||||
ple -> setPlaceholderText("Search...");
|
||||
|
||||
QVBoxLayout *pvblay = new QVBoxLayout;
|
||||
pvblay -> addLayout(phblayFind);
|
||||
pvblay -> addLayout(phblay);
|
||||
|
||||
setLayout(pvblay);
|
||||
|
||||
setWindowTitle("Add plugin");
|
||||
|
||||
QObject::connect(m_pPlugins, SIGNAL(currentItemChanged (QListWidgetItem *, QListWidgetItem *)),
|
||||
this, SLOT(showInfo(QListWidgetItem *, QListWidgetItem *)));
|
||||
|
||||
QObject::connect(m_pPlugins, SIGNAL(itemDoubleClicked (QListWidgetItem *)),
|
||||
this, SLOT(insert(QListWidgetItem *)));
|
||||
|
||||
QObject::connect(ple, SIGNAL(textChanged(const QString &)), this, SLOT(filterPlagins(const QString &)));
|
||||
|
||||
installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
void PluginsList::showInfo(QListWidgetItem *pitem, QListWidgetItem *previous)
|
||||
{
|
||||
qDebug() << "Show Info: " << pitem -> text();
|
||||
m_plblInfo -> clear();
|
||||
QString descr;
|
||||
descr += "<b>Plugin details</b><hr>";
|
||||
|
||||
GstElementFactory *factory = gst_element_factory_find(pitem -> text().toStdString().c_str());
|
||||
if(!factory)
|
||||
{
|
||||
qDebug() << "warning: " << pitem -> text() << " Not Found";
|
||||
return;
|
||||
}
|
||||
|
||||
factory = GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE(factory)));
|
||||
if(!factory)
|
||||
{
|
||||
qDebug() << "warning: " << pitem -> text() << " Not Found";
|
||||
return;
|
||||
}
|
||||
|
||||
GstPlugin *plugin = gst_plugin_feature_get_plugin (GST_PLUGIN_FEATURE (factory));
|
||||
if(!plugin)
|
||||
{
|
||||
qDebug() << "warning: " << pitem -> text() << " Not Found";
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const gchar *release_date = gst_plugin_get_release_date_string (plugin);
|
||||
const gchar *filename = gst_plugin_get_filename(plugin);
|
||||
|
||||
descr += "<b>Name</b>: " + QString(gst_plugin_get_name(plugin)) + "<br>";
|
||||
descr += "<b>Description</b>: " + QString(gst_plugin_get_description(plugin)) + "<br>";
|
||||
descr += "<b>Filename</b>: " + QString((filename != NULL) ? filename : "(null)") + "<br>";
|
||||
descr += "<b>Version</b>: " + QString(gst_plugin_get_version (plugin)) + "<br>";
|
||||
descr += "<b>License</b>: " + QString(gst_plugin_get_license (plugin)) + "<br>";
|
||||
descr += "<b>Source module</b>: " + QString(gst_plugin_get_source (plugin)) + "<br>";
|
||||
|
||||
if (release_date != NULL)
|
||||
{
|
||||
const gchar *tz = "(UTC)";
|
||||
gchar *str, *sep;
|
||||
|
||||
str = g_strdup (release_date);
|
||||
sep = strstr (str, "T");
|
||||
if (sep != NULL)
|
||||
{
|
||||
*sep = ' ';
|
||||
sep = strstr (sep + 1, "Z");
|
||||
if (sep != NULL)
|
||||
*sep = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
tz = "";
|
||||
}
|
||||
descr += "<b>Source release date</b>: " + QString(str) + " " + QString(tz) + "<br>";
|
||||
g_free (str);
|
||||
}
|
||||
descr += "<b>Binary package</b>: " + QString(gst_plugin_get_package (plugin)) + "<br>";
|
||||
descr += "<b>Origin URL</b>: " + QString(gst_plugin_get_origin (plugin)) + "<br>";
|
||||
|
||||
m_plblInfo -> setText(descr);
|
||||
}
|
||||
|
||||
|
||||
void PluginsList::insert(QListWidgetItem *pitem)
|
||||
{
|
||||
qDebug() << "Insert: " << pitem -> text();
|
||||
|
||||
if(!m_pGraph || !m_pGraph -> AddPlugin(pitem -> text().toStdString().c_str(), NULL))
|
||||
{
|
||||
QMessageBox::warning(this, "Plugin addition problem", "Plugin `" + pitem -> text() + "` insertion was FAILED");
|
||||
qDebug() << "Plugin `" << pitem -> text() << "` insertion FAILED";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PluginsList::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event -> type() == QEvent::KeyPress)
|
||||
{
|
||||
QKeyEvent *key = static_cast<QKeyEvent*>(event);
|
||||
|
||||
if((key -> key() == Qt::Key_Enter) || (key -> key() == Qt::Key_Return))
|
||||
{
|
||||
insert(m_pPlugins -> currentItem());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
|
||||
void PluginsList::filterPlagins(const QString &text)
|
||||
{
|
||||
for(std::size_t i=0; i<m_pPlugins -> count(); i++)
|
||||
{
|
||||
QListWidgetItem *pitem = m_pPlugins -> item(i);
|
||||
|
||||
if(pitem -> text().contains(text))
|
||||
pitem -> setHidden(false);
|
||||
else
|
||||
pitem -> setHidden(true);
|
||||
}
|
||||
|
||||
}
|
41
src/PluginsList.h
Normal file
41
src/PluginsList.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef PLUGINS_LIST_H_
|
||||
#define PLUGINS_LIST_H_
|
||||
|
||||
|
||||
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
|
||||
#include "GraphManager.h"
|
||||
|
||||
|
||||
class PluginsList: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PluginsList(QWidget *pwgt = NULL, Qt::WindowFlags f = 0);
|
||||
|
||||
GraphManager *m_pGraph;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev);
|
||||
|
||||
|
||||
public slots:
|
||||
void showInfo(QListWidgetItem *current, QListWidgetItem *previous);
|
||||
void insert(QListWidgetItem *);
|
||||
|
||||
private slots:
|
||||
void filterPlagins(const QString &text);
|
||||
|
||||
private:
|
||||
QLabel *m_plblInfo;
|
||||
QListWidget *m_pPlugins;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
16
src/SeekSlider.cpp
Normal file
16
src/SeekSlider.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "SeekSlider.h"
|
||||
|
||||
void SeekSlider::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if(event->button() == Qt::LeftButton)
|
||||
{
|
||||
if(orientation() == Qt::Vertical)
|
||||
setValue(minimum() + ((maximum()-minimum()) * (height()-event->y())) / height() ) ;
|
||||
else
|
||||
setValue(minimum() + ((maximum()-minimum()) * event->x()) / width() ) ;
|
||||
|
||||
event->accept();
|
||||
}
|
||||
|
||||
QSlider::mousePressEvent(event);
|
||||
};
|
16
src/SeekSlider.h
Normal file
16
src/SeekSlider.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef SEEK_SLIDER_H_
|
||||
#define SEEK_SLIDER_H_
|
||||
|
||||
|
||||
#include <QSlider>
|
||||
#include <QMouseEvent>
|
||||
|
||||
class SeekSlider: public QSlider
|
||||
{
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
15
src/main.cpp
Normal file
15
src/main.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <QApplication>
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
gst_init (&argc, &argv);
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MainWindow wgt;
|
||||
wgt.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
19
src/verinfo/verinfo.sh
Executable file
19
src/verinfo/verinfo.sh
Executable file
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
version_file=$1
|
||||
out_file=$2
|
||||
|
||||
|
||||
major=`sed -n '1p' $version_file`
|
||||
minor=`sed -n '2p' $version_file`
|
||||
|
||||
commit=`git rev-list --count HEAD`
|
||||
date=`date +'%d%m'%y`
|
||||
|
||||
|
||||
echo "#ifndef VERSION_INFO_H_" > $out_file
|
||||
echo "#define VERSION_INFO_H_" >> $out_file
|
||||
echo "" >> $out_file
|
||||
echo "#define VERSION_STR \"$major.$minor.$commit.$date\"" >> $out_file
|
||||
echo "" >> $out_file
|
||||
echo "#endif" >> $out_file
|
2
src/version
Normal file
2
src/version
Normal file
|
@ -0,0 +1,2 @@
|
|||
0
|
||||
1
|
Loading…
Reference in a new issue