├── .gitignore
├── Jenkinsfile
├── LICENSE
├── gstreamer.prf
├── pipeviz-0.10.pro
├── pipeviz.pri
├── pipeviz.pro
├── readme.md
└── src
├── CustomMenuAction.cpp
├── CustomMenuAction.h
├── CustomSettings.cpp
├── CustomSettings.h
├── ElementProperties.cpp
├── ElementProperties.h
├── FavoritesList.cpp
├── FavoritesList.h
├── GraphDisplay.cpp
├── GraphDisplay.h
├── GraphManager.cpp
├── GraphManager.h
├── Logger.cpp
├── Logger.h
├── MainWindow.cpp
├── MainWindow.h
├── PadProperties.cpp
├── PadProperties.h
├── PipelineIE.cpp
├── PipelineIE.h
├── PluginsList.cpp
├── PluginsList.h
├── SeekSlider.cpp
├── SeekSlider.h
├── main.cpp
├── verinfo
└── verinfo.sh
└── version.in
/.gitignore:
--------------------------------------------------------------------------------
1 | Makefile*
2 | debug/*
3 | object_script*
4 | pipeviz_plugin_import.cpp
5 | pipeviz
6 | *.o
7 | moc_*
8 | src/version_info.h
9 | pipeviz.pro.user
10 | pipeviz.app
11 | .qmake.stash
12 |
--------------------------------------------------------------------------------
/Jenkinsfile:
--------------------------------------------------------------------------------
1 | pipeline {
2 | agent any
3 | stages {
4 | stage('build') {
5 | steps {
6 | pwd(tmp: true)
7 | }
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/gstreamer.prf:
--------------------------------------------------------------------------------
1 | # =============================================================
2 | # This optional feature file adds GStreamer dependencies
3 | # =============================================================
4 | unix {
5 | CONFIG += link_pkgconfig
6 | PKGCONFIG += gstreamer-1.0
7 | } else {
8 |
9 | GSTREAMER_PATH = $$clean_path($$(GSTREAMER_1_0_ROOT_X86))
10 | if(isEmpty(GSTREAMER_PATH)) {
11 | GSTREAMER_PATH = $$clean_path($$(GSTREAMER_1_0_ROOT_X86_64))
12 | }
13 |
14 | if(isEmpty(GSTREAMER_PATH)|!exists($${GSTREAMER_PATH})) {
15 |
16 | text = "\"GStreamer\" not found: to be able to use the debugger, don't forget to add"
17 | text = "$${text} \"%GSTREAMER_1_0_ROOT_X86_64%\bin\" in your PATH"
18 | !build:warning("$${text}")
19 |
20 | } else {
21 |
22 | DEFINES += GST_USE_UNSTABLE_API
23 |
24 | GST_INCLUDEPATH = \
25 | $$clean_path($$GSTREAMER_PATH/include/gstreamer-1.0) \
26 | $$clean_path($$GSTREAMER_PATH/include/glib-2.0) \
27 | $$clean_path($$GSTREAMER_PATH/lib/glib-2.0/include)
28 | *-g++ {
29 | # To avoid warnings due to GStreamer, use -isystem automatically for any GStreamer system header:
30 | for(somelib, $$list($$GST_INCLUDEPATH)) {
31 | QMAKE_CXXFLAGS += -isystem $${somelib}
32 | }
33 | } else {
34 | INCLUDEPATH += $${GST_INCLUDEPATH}
35 | }
36 | unset(GST_INCLUDEPATH)
37 |
38 | win32-g++ {
39 | LIBS += \
40 | $${GSTREAMER_PATH}/lib/glib-2.0.lib \
41 | $${GSTREAMER_PATH}/lib/gobject-2.0.lib \
42 | $${GSTREAMER_PATH}/lib/gstreamer-1.0.lib
43 | } else {
44 | LIBS += \
45 | -L$$GSTREAMER_PATH/lib \
46 | -lglib-2.0 \
47 | -lgobject-2.0 \
48 | -lgstreamer-1.0
49 | }
50 | } # GStreamer found
51 | }
52 |
--------------------------------------------------------------------------------
/pipeviz-0.10.pro:
--------------------------------------------------------------------------------
1 | include(pipeviz.pri)
2 |
3 | PKGCONFIG += gstreamer-0.10
4 |
5 |
--------------------------------------------------------------------------------
/pipeviz.pri:
--------------------------------------------------------------------------------
1 | ######################################################################
2 | # Automatically generated by qmake (3.0) ?? ???. 22 21:50:14 2014
3 | ######################################################################
4 |
5 | CONFIG += qt debug
6 | TEMPLATE = app
7 | TARGET = pipeviz
8 | QT += widgets
9 | QT += xml
10 | QT += core
11 | INCLUDEPATH += $$OUT_PWD/src
12 |
13 | CONFIG += gstreamer
14 |
15 | QMAKE_CXXFLAGS += -std=c++11
16 |
17 | gitinfo.commands = $$PWD/src/verinfo/verinfo.sh $$PWD/src/version.in $$OUT_PWD/src/version_info.h
18 | gitinfo.target = $$OUT_PWD/src/version_info.h
19 |
20 | QMAKE_EXTRA_TARGETS += gitinfo
21 | PRE_TARGETDEPS += $$OUT_PWD/src/version_info.h
22 |
23 | # Input
24 | HEADERS += src/PluginsList.h \
25 | src/MainWindow.h \
26 | src/GraphManager.h \
27 | src/GraphDisplay.h \
28 | src/ElementProperties.h \
29 | src/PadProperties.h \
30 | src/PipelineIE.h \
31 | src/CustomSettings.h \
32 | src/SeekSlider.h \
33 | src/CustomMenuAction.h \
34 | src/FavoritesList.h \
35 | src/Logger.h
36 |
37 | SOURCES += src/main.cpp \
38 | src/PluginsList.cpp \
39 | src/MainWindow.cpp \
40 | src/GraphManager.cpp \
41 | src/GraphDisplay.cpp \
42 | src/ElementProperties.cpp \
43 | src/PadProperties.cpp \
44 | src/PipelineIE.cpp \
45 | src/CustomSettings.cpp \
46 | src/SeekSlider.cpp \
47 | src/CustomMenuAction.cpp \
48 | src/FavoritesList.cpp \
49 | src/Logger.cpp
50 |
--------------------------------------------------------------------------------
/pipeviz.pro:
--------------------------------------------------------------------------------
1 | # Location of our own features:
2 | command = $$[QT_INSTALL_BINS]/qmake -set QMAKEFEATURES $$_PRO_FILE_PWD_
3 | system($$command)|error("Failed to run: $$command")
4 |
5 | include(pipeviz.pri)
6 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | pipeviz
2 | ==========
3 |
4 | Pipeviz is a graphedit for gstreamer-1.0. This is a gui tool for constructing and testing gstreamer pipelines.
5 |
6 | It allows you:
7 |
8 | * to construct the pipelines via the gui interface
9 |
10 | * to test different types of pipes easy
11 |
12 | * save and open your graphs
13 |
14 | Who might be interested in it?
15 |
16 | * quality assurance
17 |
18 | * technical support
19 |
20 | * software engineers
21 |
22 |
23 | 
24 |
25 | Pre-requirements:
26 | -----
27 |
28 | * qt (4.0 5.0)
29 |
30 | * gstreamer-1.0
31 |
32 | * pkgconfig
33 |
34 |
35 |
36 | Building:
37 | -----
38 |
39 | cd pipeviz
40 |
41 | QMAKEFEATURES=. qmake pipeviz.pro
42 |
43 | make gitinfo
44 |
45 | make
46 |
47 |
48 |
49 | Prebuilt binaries
50 | -----
51 |
52 | Prebuilt binaries for windows are available.
53 |
54 | [Latest Release](https://github.com/virinext/pipeviz/releases/latest)
55 |
--------------------------------------------------------------------------------
/src/CustomMenuAction.cpp:
--------------------------------------------------------------------------------
1 | #include "CustomMenuAction.h"
2 |
3 | CustomMenuAction::CustomMenuAction (const QString& displayName,
4 | QObject * parent)
5 | : QAction (displayName, parent),
6 | m_name (displayName)
7 | {
8 | }
9 |
10 | CustomMenuAction::CustomMenuAction (const QString& displayName,
11 | const QString& name, QObject * parent)
12 | : QAction (displayName, parent),
13 | m_name (name)
14 | {
15 | }
16 |
--------------------------------------------------------------------------------
/src/CustomMenuAction.h:
--------------------------------------------------------------------------------
1 | #ifndef CUSTOM_MENU_ACTION_H_
2 | #define CUSTOM_MENU_ACTION_H_
3 |
4 | #include
5 |
6 | class CustomMenuAction: public QAction
7 | {
8 | public:
9 | CustomMenuAction(const QString& displayName, QObject * parent);
10 | CustomMenuAction(const QString& displayName, const QString& name, QObject * parent);
11 |
12 | QString getName() {return m_name;}
13 |
14 | private:
15 | QString m_name;
16 | };
17 |
18 | #endif //CUSTOM_MENU_ACTION_H_
19 |
--------------------------------------------------------------------------------
/src/CustomSettings.cpp:
--------------------------------------------------------------------------------
1 | #include "CustomSettings.h"
2 |
3 | #include
4 |
5 | #define COMPANY_NAME "virinext"
6 | #define APPLICATION_NAME "pipeviz"
7 |
8 | void
9 | CustomSettings::saveLastIODirectory (const QString &name)
10 | {
11 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
12 | settings.setValue ("last_directory", name);
13 | }
14 |
15 | QString
16 | CustomSettings::lastIODirectory ()
17 | {
18 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
19 | QString res = settings.value ("last_directory").toString ();
20 |
21 | if (res.isEmpty ())
22 | res = "./";
23 |
24 | return res;
25 | }
26 |
27 | void
28 | CustomSettings::saveFavoriteList (const QStringList &favorite_list)
29 | {
30 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
31 | settings.setValue("favorite_list", QVariant::fromValue(favorite_list));
32 | }
33 |
34 | QStringList
35 | CustomSettings::loadFavoriteList ()
36 | {
37 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
38 | QStringList data = settings.value("favorite_list").value();
39 |
40 | return data;
41 | }
42 |
43 | void
44 | CustomSettings::saveMainWindowGeometry (const QByteArray &geometry)
45 | {
46 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
47 | settings.setValue ("geometry", geometry);
48 | }
49 |
50 | QByteArray
51 | CustomSettings::mainWindowGeometry ()
52 | {
53 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
54 | return settings.value ("geometry").toByteArray ();
55 | }
56 |
57 | void
58 | CustomSettings::saveGstDebugString (const QString &string)
59 | {
60 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
61 | settings.setValue ("gst_log_string", string);
62 | }
63 |
64 | QString
65 | CustomSettings::lastGstDebugString ()
66 | {
67 | QSettings settings (COMPANY_NAME, APPLICATION_NAME);
68 | QString res = settings.value ("gst_log_string").toString ();
69 |
70 | if (res.isEmpty ())
71 | res = "GST_DEBUG=*:5";
72 |
73 | return res;
74 | }
75 |
--------------------------------------------------------------------------------
/src/CustomSettings.h:
--------------------------------------------------------------------------------
1 | #ifndef CUSTOM_SETTINGS_H_
2 | #define CUSTOM_SETTINGS_H_
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | namespace CustomSettings
9 | {
10 | void saveLastIODirectory(const QString &name);
11 | QString lastIODirectory();
12 | void saveFavoriteList(const QStringList &name);
13 | QStringList loadFavoriteList();
14 |
15 | void saveGstDebugString(const QString &name);
16 | QString lastGstDebugString();
17 |
18 | void saveMainWindowGeometry(const QByteArray &geometry);
19 | QByteArray mainWindowGeometry();
20 | }
21 |
22 | #endif
23 |
--------------------------------------------------------------------------------
/src/ElementProperties.cpp:
--------------------------------------------------------------------------------
1 | #include "ElementProperties.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include
12 |
13 | ElementProperties::ElementProperties (QSharedPointer pGraph,
14 | const char *name, QWidget *parent,
15 | Qt::WindowFlags flags)
16 | : QWidget (parent, flags),
17 | m_pGraphManager (pGraph),
18 | m_name (name)
19 | {
20 | setWindowTitle (QString (name) + " properties");
21 |
22 | create ();
23 | }
24 |
25 | void
26 | ElementProperties::addParamEnum (GParamSpec *param, GstElement *element,
27 | QGridLayout *play)
28 | {
29 | GValue value = G_VALUE_INIT;
30 |
31 | g_value_init (&value, param->value_type);
32 | if (param->flags & G_PARAM_READABLE)
33 | g_object_get_property (G_OBJECT (element), param->name, &value);
34 | else {
35 | const GValue *valueDef = g_param_spec_get_default_value (param);
36 | g_value_copy (valueDef, &value);
37 | }
38 |
39 | QString propertyName = g_param_spec_get_name (param);
40 | int propertyValue;
41 |
42 | propertyValue = g_value_get_enum (&value);
43 |
44 | GParamSpecEnum *penumSpec = G_PARAM_SPEC_ENUM (param);
45 |
46 | if (!penumSpec)
47 | return;
48 |
49 | QComboBox *pcomBox = new QComboBox;
50 |
51 | for (std::size_t i = 0; i < penumSpec->enum_class->n_values; i++) {
52 | QVariant var (penumSpec->enum_class->values[i].value);
53 | QString valueName = penumSpec->enum_class->values[i].value_name;
54 |
55 | pcomBox->addItem (valueName, var);
56 |
57 | if (penumSpec->enum_class->values[i].value == propertyValue)
58 | pcomBox->setCurrentIndex (i);
59 | }
60 |
61 | int row = play->rowCount ();
62 | play->addWidget (new QLabel (propertyName), row, 0);
63 | play->addWidget (pcomBox, row, 1);
64 | m_values.insert (propertyName, pcomBox);
65 | }
66 |
67 | void
68 | ElementProperties::addParamFlags (GParamSpec *param, GstElement *element,
69 | QGridLayout *play)
70 | {
71 | GValue value = G_VALUE_INIT;
72 |
73 | g_value_init (&value, param->value_type);
74 | if (param->flags & G_PARAM_READABLE)
75 | g_object_get_property (G_OBJECT (element), param->name, &value);
76 | else {
77 | const GValue *valueDef = g_param_spec_get_default_value (param);
78 | g_value_copy (valueDef, &value);
79 | }
80 |
81 | QString propertyName = g_param_spec_get_name (param);
82 | size_t propertyValue;
83 |
84 | propertyValue = g_value_get_flags (&value);
85 |
86 | GParamSpecFlags *pflagsSpec = G_PARAM_SPEC_FLAGS (param);
87 |
88 | if (!pflagsSpec)
89 | return;
90 |
91 | QComboBox *pcomBox = new QComboBox;
92 |
93 | for (std::size_t i = 0; i < pflagsSpec->flags_class->n_values; i++) {
94 | QVariant var (pflagsSpec->flags_class->values[i].value);
95 | QString valueName = pflagsSpec->flags_class->values[i].value_name;
96 |
97 | pcomBox->addItem (valueName, var);
98 |
99 | if (pflagsSpec->flags_class->values[i].value == propertyValue)
100 | pcomBox->setCurrentIndex (i);
101 | }
102 |
103 | int row = play->rowCount ();
104 |
105 | play->addWidget (new QLabel (propertyName), row, 0);
106 |
107 | play->addWidget (pcomBox, row, 1);
108 |
109 | m_values.insert (propertyName, pcomBox);
110 | }
111 |
112 | void
113 | ElementProperties::addParamSimple (GParamSpec *param, GstElement *element,
114 | QGridLayout *play)
115 | {
116 | bool readOnly = true;
117 |
118 | if (param->flags & G_PARAM_WRITABLE)
119 | readOnly = false;
120 |
121 | GValue value = G_VALUE_INIT;
122 |
123 | g_value_init (&value, param->value_type);
124 | if (param->flags & G_PARAM_READABLE)
125 | g_object_get_property (G_OBJECT (element), param->name, &value);
126 | else {
127 | const GValue *valueDef = g_param_spec_get_default_value (param);
128 | g_value_copy (valueDef, &value);
129 | }
130 |
131 | QString propertyName = g_param_spec_get_name (param);
132 | QString propertyValue;
133 | GType type = G_VALUE_TYPE (&value);
134 |
135 | bool skip = false;
136 |
137 | switch (type) {
138 | case G_TYPE_STRING: {
139 | const char *string_val = g_value_get_string (&value);
140 | propertyValue = string_val;
141 | break;
142 | }
143 | case G_TYPE_BOOLEAN: {
144 | gboolean bool_val = g_value_get_boolean (&value);
145 | propertyValue = QString::number (bool_val);
146 | break;
147 | }
148 | case G_TYPE_ULONG: {
149 | propertyValue = QString::number (g_value_get_ulong (&value));
150 | break;
151 | }
152 | case G_TYPE_LONG: {
153 | propertyValue = QString::number (g_value_get_long (&value));
154 | break;
155 | }
156 | case G_TYPE_UINT: {
157 | propertyValue = QString::number (g_value_get_uint (&value));
158 | break;
159 | }
160 | case G_TYPE_INT: {
161 | propertyValue = QString::number (g_value_get_int (&value));
162 | break;
163 | }
164 | case G_TYPE_UINT64: {
165 | propertyValue = QString::number (g_value_get_uint64 (&value));
166 | break;
167 | }
168 | case G_TYPE_INT64: {
169 | propertyValue = QString::number (g_value_get_int64 (&value));
170 | break;
171 | }
172 | case G_TYPE_FLOAT: {
173 | propertyValue = QString::number (g_value_get_float (&value));
174 | break;
175 | }
176 | case G_TYPE_DOUBLE: {
177 | propertyValue = QString::number (g_value_get_double (&value));
178 | break;
179 | }
180 | case G_TYPE_CHAR: {
181 | propertyValue = QString::number (g_value_get_schar (&value));
182 | break;
183 | }
184 | case G_TYPE_UCHAR: {
185 | propertyValue = QString::number (g_value_get_uchar (&value));
186 | break;
187 | }
188 |
189 | default: {
190 | if (type == g_type_from_name("GstCaps")) {
191 | GstCaps *gstcaps;
192 | g_object_get (G_OBJECT (element), param->name, &gstcaps, NULL);
193 | const char *string_val = gst_caps_to_string (gstcaps);
194 | if (gstcaps == NULL)
195 | string_val = "ANY";
196 | propertyValue = string_val;
197 | break;
198 | }
199 |
200 | skip = true;
201 | LOG_INFO("property %s not supported", propertyName.toStdString ().c_str ());
202 | break;
203 | }
204 | };
205 |
206 | int row = play->rowCount ();
207 |
208 | play->addWidget (new QLabel (propertyName), row, 0);
209 |
210 | QLineEdit *ple = new QLineEdit (propertyValue);
211 | ple->setReadOnly (readOnly);
212 | play->addWidget (ple, row, 1);
213 | if (!skip)
214 | m_values.insert (propertyName, ple);
215 | else
216 | ple->setReadOnly (true);
217 | }
218 |
219 | void
220 | ElementProperties::create ()
221 | {
222 | GstElement *element = gst_bin_get_by_name (
223 | GST_BIN (m_pGraphManager->m_pGraph), m_name.toStdString ().c_str ());
224 |
225 | if (!element)
226 | return;
227 |
228 | QGridLayout *play = new QGridLayout;
229 |
230 | GParamSpec **prop_specs;
231 | guint num_props;
232 |
233 | prop_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element),
234 | &num_props);
235 |
236 | for (std::size_t i = 0; i < num_props; i++) {
237 | GParamSpec *param = prop_specs[i];
238 |
239 | if (G_IS_PARAM_SPEC_ENUM (param))
240 | addParamEnum (param, element, play);
241 | else if (G_IS_PARAM_SPEC_FLAGS (param))
242 | addParamFlags (param, element, play);
243 | else
244 | addParamSimple (param, element, play);
245 | }
246 |
247 | QVBoxLayout *pvblay = new QVBoxLayout;
248 | QWidget *pwgt = new QWidget (this);
249 | pwgt->setLayout (play);
250 | QScrollArea *pscroll = new QScrollArea (this);
251 | pscroll->setWidget (pwgt);
252 |
253 | pvblay->addWidget (pscroll);
254 |
255 | QHBoxLayout *phblay = new QHBoxLayout;
256 |
257 | QPushButton *pcmdApply = new QPushButton ("Apply");
258 | QPushButton *pcmdOk = new QPushButton ("OK");
259 | QPushButton *pcmdCancel = new QPushButton ("Cancel");
260 |
261 | phblay->addStretch (1);
262 | phblay->addWidget (pcmdApply);
263 | phblay->addWidget (pcmdCancel);
264 | phblay->addWidget (pcmdOk);
265 |
266 | pvblay->addLayout (phblay);
267 |
268 | QObject::connect (pcmdApply, SIGNAL (clicked ()), this,
269 | SLOT (applyClicked ()));
270 | QObject::connect (pcmdCancel, SIGNAL (clicked ()), this, SLOT (close ()));
271 | QObject::connect (pcmdOk, SIGNAL (clicked ()), this, SLOT (okClicked ()));
272 |
273 | setLayout (pvblay);
274 |
275 | g_free (prop_specs);
276 | gst_object_unref (element);
277 |
278 | }
279 |
280 | void
281 | ElementProperties::applyClicked ()
282 | {
283 | GstElement *element = gst_bin_get_by_name (
284 | GST_BIN (m_pGraphManager->m_pGraph), m_name.toStdString ().c_str ());
285 |
286 | if (!element)
287 | return;
288 |
289 | QMap::iterator itr = m_values.begin ();
290 |
291 | for (; itr != m_values.end (); itr++) {
292 | GParamSpec *param = g_object_class_find_property (
293 | G_OBJECT_GET_CLASS (element), itr.key ().toStdString ().c_str ());
294 |
295 | if (!param) {
296 | LOG_INFO("problem with setting %s property", itr.key ().toStdString ().c_str ());
297 | continue;
298 | }
299 |
300 | if (!(param->flags & G_PARAM_WRITABLE))
301 | continue;
302 |
303 | QString valStr;
304 |
305 | if (dynamic_cast (itr.value ()))
306 | valStr = ((QLineEdit *) itr.value ())->text ();
307 | else if (dynamic_cast (itr.value ())) {
308 | QComboBox *pcomBox = (QComboBox *) itr.value ();
309 | int val = pcomBox->itemData (pcomBox->currentIndex ()).toInt ();
310 | valStr = QString::number (val);
311 | }
312 |
313 | std::string tmpStr = itr.key ().toStdString ();
314 | const char *propName = tmpStr.c_str ();
315 |
316 | if (G_IS_PARAM_SPEC_ENUM (param) || G_IS_PARAM_SPEC_FLAGS (param)) {
317 | if (dynamic_cast (itr.value ())) {
318 | QComboBox *pcomBox = (QComboBox *) itr.value ();
319 | int val = pcomBox->itemData (pcomBox->currentIndex ()).toInt ();
320 | g_object_set (G_OBJECT (element), propName, val, NULL);
321 | }
322 | }
323 | else {
324 | GType type = param->value_type;
325 | switch (type) {
326 | case G_TYPE_STRING: {
327 | g_object_set (G_OBJECT (element), propName,
328 | valStr.toStdString ().c_str (), NULL);
329 | break;
330 | }
331 | case G_TYPE_BOOLEAN: {
332 | gboolean val = valStr.toInt ();
333 | g_object_set (G_OBJECT (element), propName, val, NULL);
334 | break;
335 | }
336 | case G_TYPE_ULONG: {
337 | gulong val = valStr.toULong ();
338 | g_object_set (G_OBJECT (element), propName, val, NULL);
339 | break;
340 | }
341 | case G_TYPE_LONG: {
342 | glong val = valStr.toLong ();
343 | g_object_set (G_OBJECT (element), propName, val, NULL);
344 | break;
345 | }
346 | case G_TYPE_UINT: {
347 | guint val = valStr.toUInt ();
348 | g_object_set (G_OBJECT (element), propName, val, NULL);
349 | break;
350 | }
351 | case G_TYPE_INT: {
352 | gint val = valStr.toInt ();
353 | g_object_set (G_OBJECT (element), propName, val, NULL);
354 | break;
355 | }
356 | case G_TYPE_UINT64: {
357 | guint64 val = valStr.toULongLong ();
358 | g_object_set (G_OBJECT (element), propName, val, NULL);
359 | break;
360 | }
361 | case G_TYPE_INT64: {
362 | gint64 val = valStr.toLongLong ();
363 | g_object_set (G_OBJECT (element), propName, val, NULL);
364 | break;
365 | }
366 | case G_TYPE_FLOAT: {
367 | gfloat val = valStr.toFloat ();
368 | g_object_set (G_OBJECT (element), propName, val, NULL);
369 | break;
370 | }
371 | case G_TYPE_DOUBLE: {
372 | gdouble val = valStr.toDouble ();
373 | g_object_set (G_OBJECT (element), propName, val, NULL);
374 | break;
375 | }
376 | case G_TYPE_CHAR: {
377 | gchar val = valStr.toInt ();
378 | g_object_set (G_OBJECT (element), propName, val, NULL);
379 | break;
380 | }
381 | case G_TYPE_UCHAR: {
382 | guchar val = valStr.toUInt ();
383 | g_object_set (G_OBJECT (element), propName, val, NULL);
384 | break;
385 | }
386 | default: {
387 | if (type == g_type_from_name("GstCaps")) {
388 | GstCaps *oldval;
389 | GstCaps *newval = gst_caps_from_string (valStr.toStdString ().c_str ());
390 | g_object_get (G_OBJECT (element), propName, &oldval, NULL);
391 |
392 | if (oldval != newval && oldval != NULL) {
393 | /* Release old */
394 | gst_caps_unref (oldval);
395 | }
396 |
397 | g_object_set (G_OBJECT (element), propName, newval, NULL);
398 | break;
399 | }
400 |
401 | LOG_INFO("property %s not supported", itr.key ().constData());
402 | break;
403 | }
404 | };
405 | }
406 | }
407 |
408 | gst_object_unref (element);
409 |
410 | delete layout ();
411 | qDeleteAll (
412 | children ());
413 |
414 | create ();
415 | }
416 |
417 | void
418 | ElementProperties::okClicked ()
419 | {
420 | applyClicked ();
421 | close ();
422 | }
423 |
--------------------------------------------------------------------------------
/src/ElementProperties.h:
--------------------------------------------------------------------------------
1 | #ifndef ELEMENT_PROPERTIES_H_
2 | #define ELEMENT_PROPERTIES_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | #include "GraphManager.h"
12 |
13 | class ElementProperties: public QWidget
14 | {
15 | Q_OBJECT
16 | public:
17 | ElementProperties(QSharedPointer pGraphManager, const char *name,
18 | QWidget *parent = 0, Qt::WindowFlags flags = 0);
19 |
20 | private slots:
21 | void applyClicked();
22 | void okClicked();
23 |
24 | private:
25 | QSharedPointer m_pGraphManager;
26 | QMap m_values;
27 | QString m_name;
28 |
29 | void create();
30 | void addParamSimple(GParamSpec *value, GstElement *element, QGridLayout *play);
31 | void addParamEnum(GParamSpec *value, GstElement *element, QGridLayout *play);
32 | void addParamFlags(GParamSpec *value, GstElement *element, QGridLayout *play);
33 | };
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/FavoritesList.cpp:
--------------------------------------------------------------------------------
1 | #include "FavoritesList.h"
2 | #include "CustomSettings.h"
3 | #include "Logger.h"
4 |
5 | #include
6 |
7 | #include
8 |
9 |
10 | FavoritesList::FavoritesList (QWidget *pwgt)
11 | : QListWidget (pwgt)
12 | {
13 | loadFavorites();
14 | }
15 |
16 | FavoritesList::~FavoritesList ()
17 | {
18 | }
19 |
20 | int FavoritesList::isFavorite(const QString& plugin_name)
21 | {
22 | for (int i = 0; i < this->count (); i++) {
23 | QListWidgetItem *pitem = this->item (i);
24 | if (pitem->text () == plugin_name)
25 | return i;
26 | }
27 | return -1;
28 | }
29 |
30 | void FavoritesList::addFavorite (const QString& plugin_name)
31 | {
32 | if (isFavorite(plugin_name) == -1)
33 | this->addItem(plugin_name);
34 | saveFavorites();
35 | }
36 |
37 | void FavoritesList::removeFavorite (const QString& plugin_name)
38 | {
39 | int favorite = isFavorite(plugin_name);
40 | if (favorite != -1)
41 | delete this->takeItem(this->row(this->item(favorite)));
42 | saveFavorites();
43 | }
44 |
45 | void FavoritesList::loadFavorites()
46 | {
47 | QStringList favorites = CustomSettings::loadFavoriteList();
48 | foreach (QString plugin_name, favorites) {
49 | this->addItem(plugin_name);
50 | }
51 | LOG_INFO("Just load favorites");
52 | }
53 |
54 | void FavoritesList::saveFavorites()
55 | {
56 | QStringList favorites;
57 |
58 | for (int i = 0; i < this->count (); i++) {
59 | QListWidgetItem *pitem = this->item (i);
60 | favorites << pitem->text();
61 | }
62 | LOG_INFO("About to save favorites");
63 | CustomSettings::saveFavoriteList(favorites);
64 | }
65 |
--------------------------------------------------------------------------------
/src/FavoritesList.h:
--------------------------------------------------------------------------------
1 | #ifndef FAVORITES_LIST_H_
2 | #define FAVORITES_LIST_H_
3 |
4 | #include
5 | #include
6 |
7 | class FavoritesList: public QListWidget
8 | {
9 | Q_OBJECT
10 | public:
11 | FavoritesList(QWidget *pwgt = NULL);
12 | ~FavoritesList();
13 |
14 | int isFavorite(const QString& plugin_name);
15 |
16 | void addFavorite(const QString& plugin_name);
17 | void removeFavorite(const QString& plugin_name);
18 |
19 | private:
20 | void loadFavorites();
21 | void saveFavorites();
22 | };
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/src/GraphDisplay.cpp:
--------------------------------------------------------------------------------
1 | #include "GraphDisplay.h"
2 |
3 | #include
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "ElementProperties.h"
15 | #include "PadProperties.h"
16 | #include "CustomMenuAction.h"
17 | #include "PluginsList.h"
18 |
19 | #define PAD_SIZE 8
20 | #define PAD_SIZE_ACTION 16
21 |
22 | GraphDisplay::GraphDisplay (QWidget *parent, Qt::WindowFlags f)
23 | : QWidget (parent, f)
24 | {
25 | setFocusPolicy (Qt::WheelFocus);
26 | setMouseTracking (true);
27 | }
28 |
29 | ElementInfo*
30 | GraphDisplay::getElement (std::size_t elementId)
31 | {
32 | ElementInfo* element = NULL;
33 | std::size_t i = 0;
34 | for (; i < m_info.size (); i++) {
35 | if (m_info[i].m_id == elementId) {
36 | element = &m_info[i];
37 | break;
38 | }
39 | }
40 | return element;
41 | }
42 |
43 | PadInfo*
44 | GraphDisplay::getPad (std::size_t elementId, std::size_t padId)
45 | {
46 | PadInfo* pad = NULL;
47 | ElementInfo* element = getElement (elementId);
48 | if (!element)
49 | return NULL;
50 | std::size_t j = 0;
51 | for (; j < element->m_pads.size (); j++)
52 | if (element->m_pads[j].m_id == padId) {
53 | pad = &element->m_pads[j];
54 | break;
55 | }
56 | return pad;
57 | }
58 |
59 | void
60 | GraphDisplay::updateDisplayInfoIds ()
61 | {
62 | for (std::size_t i = 0; i < m_info.size (); i++) {
63 | for (std::size_t j = 0; j < m_displayInfo.size (); j++) {
64 | if (m_info[i].m_name == m_displayInfo[j].m_name) {
65 | m_displayInfo[j].m_id = m_info[i].m_id;
66 | for (std::size_t k = 0; k < m_displayInfo.size (); k++) {
67 | if (k != j && m_displayInfo[j].m_id == m_displayInfo[k].m_id)
68 | m_displayInfo[k].m_id = (size_t) -1;
69 | }
70 | }
71 | }
72 | }
73 | }
74 |
75 | void
76 | GraphDisplay::update (const std::vector &info)
77 | {
78 | bool needUpdate = false;
79 |
80 | if (m_info.size () != info.size ())
81 | needUpdate = true;
82 |
83 | if (!needUpdate) {
84 | for (std::size_t i = 0; i < info.size (); i++) {
85 | std::size_t j = 0;
86 |
87 | for (; j < m_info.size (); j++) {
88 | if (info[i].m_name == m_info[j].m_name)
89 | break;
90 | }
91 |
92 | if (j == m_info.size ()) {
93 | needUpdate = true;
94 | break;
95 | }
96 |
97 | if (info[i].m_pads != m_info[j].m_pads) {
98 | needUpdate = true;
99 | break;
100 | }
101 |
102 | if (info[i].m_connections != m_info[j].m_connections) {
103 | needUpdate = true;
104 | break;
105 | }
106 | }
107 | }
108 |
109 | if (needUpdate) {
110 | m_info = info;
111 | updateDisplayInfoIds ();
112 | calculatePositions ();
113 | repaint ();
114 | }
115 | }
116 |
117 | void
118 | GraphDisplay::paintEvent (QPaintEvent *event)
119 | {
120 | Q_UNUSED(event);
121 | QPainter painter (this);
122 | QPen defaultPen = painter.pen ();
123 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
124 | if (m_displayInfo[i].m_isSelected)
125 | painter.setPen (QPen (Qt::blue));
126 |
127 | painter.drawRect (m_displayInfo[i].m_rect);
128 |
129 | painter.setPen (defaultPen);
130 |
131 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
132 |
133 | QPoint point = getPadPosition (m_info[i].m_id, m_info[i].m_pads[j].m_id);
134 |
135 | int xPos, yPos;
136 | xPos = point.x ();
137 | yPos = point.y ();
138 |
139 | xPos -= PAD_SIZE / 2;
140 | yPos -= PAD_SIZE / 2;
141 |
142 | painter.fillRect (xPos, yPos, PAD_SIZE, PAD_SIZE, Qt::black);
143 |
144 | QPoint textPos;
145 |
146 | QRect rect = painter.boundingRect (
147 | 0, 0, width (), height (), Qt::AlignLeft | Qt::AlignTop,
148 | QString (m_info[i].m_pads[j].m_name.c_str ()));
149 | if (m_info[i].m_pads[j].m_type == PadInfo::Out)
150 | textPos = QPoint (point.x () - PAD_SIZE - rect.width (),
151 | point.y () + PAD_SIZE / 2);
152 | else if (m_info[i].m_pads[j].m_type == PadInfo::In)
153 | textPos = QPoint (point.x () + PAD_SIZE, point.y () + PAD_SIZE / 2);
154 | painter.drawText (textPos, QString (m_info[i].m_pads[j].m_name.c_str ()));
155 |
156 | if (m_info[i].m_connections[j].m_elementId != ((size_t) -1)
157 | && m_info[i].m_connections[j].m_padId != ((size_t) -1)) {
158 | xPos = point.x ();
159 | yPos = point.y ();
160 |
161 | point = getPadPosition (m_info[i].m_connections[j].m_elementId,
162 | m_info[i].m_connections[j].m_padId);
163 | int xPosPeer, yPosPeer;
164 |
165 | xPosPeer = point.x ();
166 | yPosPeer = point.y ();
167 |
168 | painter.drawLine (xPos, yPos, xPosPeer, yPosPeer);
169 | }
170 |
171 | }
172 |
173 | painter.drawText (m_displayInfo[i].m_rect.topLeft () + QPoint (10, 15),
174 | QString (m_displayInfo[i].m_name.c_str ()));
175 | }
176 |
177 | if (m_moveInfo.m_action == MakeConnect) {
178 | painter.drawLine (m_moveInfo.m_position, m_moveInfo.m_startPosition);
179 | }
180 | else if (m_moveInfo.m_action == Select) {
181 | if (!m_moveInfo.m_position.isNull ()) {
182 | painter.setPen (Qt::DashLine);
183 | painter.drawRect (
184 | QRect (m_moveInfo.m_startPosition, m_moveInfo.m_position));
185 | }
186 | }
187 | }
188 |
189 | GraphDisplay::ElementDisplayInfo
190 | GraphDisplay::calculateOnePosition (const ElementInfo &info)
191 | {
192 | ElementDisplayInfo displayInfo;
193 | displayInfo.m_id = info.m_id;
194 | displayInfo.m_name = info.m_name;
195 | displayInfo.m_isSelected = false;
196 |
197 | int width = 150;
198 | int height = 50;
199 |
200 | int numInPads, numOutPads;
201 | numInPads = numOutPads = 0;
202 |
203 | for (std::size_t j = 0; j < info.m_pads.size (); j++) {
204 | if (info.m_pads[j].m_type == PadInfo::Out)
205 | numOutPads++;
206 | else if (info.m_pads[j].m_type == PadInfo::In)
207 | numInPads++;
208 | }
209 |
210 | if (std::max (numInPads, numOutPads) >= 1)
211 | height += (std::max (numInPads, numOutPads) - 1) * 25;
212 |
213 | int curX, curY;
214 | curX = curY = 10;
215 |
216 | QRect rect (curX, curY, width, height);
217 |
218 | while (true) {
219 | rect = QRect (curX, curY, width, height);
220 | QRect rectTest (curX, curY - 15, width + 15, height + 15);
221 | bool noIntersects = true;
222 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
223 | if (rectTest.intersects (m_displayInfo[i].m_rect)) {
224 | noIntersects = false;
225 | break;
226 | }
227 | }
228 |
229 | if (noIntersects)
230 | break;
231 |
232 | curY += 25;
233 | }
234 |
235 | displayInfo.m_rect = rect;
236 |
237 | return displayInfo;
238 |
239 | }
240 |
241 | void
242 | GraphDisplay::calculatePositions ()
243 | {
244 | while (true) {
245 | std::size_t i = 0;
246 | for (; i < m_displayInfo.size (); i++) {
247 | std::size_t j = 0;
248 | for (; j < m_info.size (); j++) {
249 | if (m_displayInfo[i].m_id == m_info[j].m_id)
250 | break;
251 | }
252 |
253 | if (j == m_info.size ()) {
254 | m_displayInfo.erase (m_displayInfo.begin () + i);
255 | break;
256 | }
257 | }
258 |
259 | if (i >= m_displayInfo.size ())
260 | break;
261 | }
262 |
263 | std::size_t i = 0;
264 | for (; i < m_info.size (); i++) {
265 | std::size_t j = 0;
266 | for (; j < m_displayInfo.size (); j++) {
267 | if (m_displayInfo[j].m_id == m_info[i].m_id)
268 | break;
269 | }
270 |
271 | if (j == m_displayInfo.size ())
272 | m_displayInfo.push_back (calculateOnePosition (m_info[i]));
273 | }
274 |
275 | std::vector reorderedDisplayInfo (m_info.size ());
276 | for (std::size_t i = 0; i < m_info.size (); i++) {
277 | for (std::size_t j = 0; j < m_displayInfo.size (); j++) {
278 | if (m_displayInfo[j].m_id == m_info[i].m_id) {
279 | reorderedDisplayInfo[i] = m_displayInfo[j];
280 | break;
281 | }
282 | }
283 | }
284 |
285 | m_displayInfo = reorderedDisplayInfo;
286 | }
287 |
288 | void
289 | GraphDisplay::mousePressEvent (QMouseEvent *event)
290 | {
291 | std::size_t elementId, padId;
292 | getIdByPosition (event->pos (), elementId, padId);
293 |
294 | if (event->buttons () & Qt::RightButton) {
295 | showContextMenu (event);
296 | }
297 | else {
298 | if (padId != ((size_t) -1)) {
299 | m_moveInfo.m_padId = padId;
300 | m_moveInfo.m_elementId = elementId;
301 | m_moveInfo.m_position = event->pos ();
302 | m_moveInfo.m_action = MakeConnect;
303 | m_moveInfo.m_startPosition = event->pos ();
304 | }
305 | else if (elementId != ((size_t) -1)) {
306 | m_moveInfo.m_elementId = elementId;
307 | m_moveInfo.m_padId = -1;
308 | m_moveInfo.m_position = event->pos ();
309 | m_moveInfo.m_action = MoveComponent;
310 | m_moveInfo.m_startPosition = event->pos ();
311 | }
312 | else {
313 | m_moveInfo.m_startPosition = event->pos ();
314 | m_moveInfo.m_action = Select;
315 | m_moveInfo.m_position = QPoint ();
316 | }
317 | }
318 |
319 | for (std::size_t i = 0; i < m_displayInfo.size (); i++)
320 | m_displayInfo[i].m_isSelected = false;
321 | }
322 |
323 | void
324 | GraphDisplay::mouseReleaseEvent (QMouseEvent *event)
325 | {
326 | if (m_moveInfo.m_action == MakeConnect) {
327 | std::size_t elementId, padId;
328 | getIdByPosition (event->pos (), elementId, padId);
329 |
330 | if (elementId != ((size_t) -1) && padId != ((size_t) -1)) {
331 | ElementInfo infoSrc, infoDst;
332 | const char *srcPad, *dstPad;
333 | srcPad = NULL;
334 | dstPad = NULL;
335 |
336 | for (std::size_t i = 0; i < m_info.size (); i++) {
337 | if (m_info[i].m_id == m_moveInfo.m_elementId) {
338 | infoSrc = m_info[i];
339 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
340 | if (m_info[i].m_pads[j].m_id == m_moveInfo.m_padId) {
341 | srcPad = m_info[i].m_pads[j].m_name.c_str ();
342 | break;
343 | }
344 | }
345 | }
346 | if (m_info[i].m_id == elementId) {
347 | infoDst = m_info[i];
348 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
349 | if (m_info[i].m_pads[j].m_id == padId) {
350 | dstPad = m_info[i].m_pads[j].m_name.c_str ();
351 | break;
352 | }
353 | }
354 | }
355 |
356 | if (srcPad != NULL && dstPad != NULL)
357 | break;
358 | }
359 | if (!infoSrc.m_name.compare (infoDst.m_name)) {
360 | LOG_INFO("infoSrc == infoDst. No need to connect anything");
361 | goto exit;
362 |
363 | }
364 |
365 | assert(srcPad != NULL && dstPad != NULL);
366 |
367 | LOG_INFO("Connection from %s:%s to %s:%s", infoSrc.m_name.c_str (), srcPad, infoDst.m_name.c_str (), dstPad);
368 |
369 | if (!m_pGraph->Connect (infoSrc.m_name.c_str (), srcPad,
370 | infoDst.m_name.c_str (), dstPad)) {
371 | QString msg;
372 | msg = "Connection ";
373 | msg += QString (infoSrc.m_name.c_str ()) + ":" + srcPad;
374 | msg += " => ";
375 | msg += QString (infoDst.m_name.c_str ()) + ":" + dstPad;
376 | msg += " was FAILED";
377 |
378 | QMessageBox::warning (this, "Connection failed", msg);
379 | }
380 |
381 | m_info = m_pGraph->GetInfo ();
382 | updateDisplayInfoIds ();
383 | if (g_str_has_prefix (infoDst.m_name.c_str (), "decodebin")) {
384 | m_pGraph->Play ();
385 | LOG_INFO("Launch play to discover the new pad");
386 | }
387 | }
388 | }
389 | else if (m_moveInfo.m_action == Select) {
390 | std::size_t width = std::abs (
391 | m_moveInfo.m_position.x () - m_moveInfo.m_startPosition.x ());
392 | std::size_t height = std::abs (
393 | m_moveInfo.m_position.y () - m_moveInfo.m_startPosition.y ());
394 |
395 | if (!m_moveInfo.m_position.isNull () && width * height > 5) {
396 | QRect selectionRect (m_moveInfo.m_startPosition, m_moveInfo.m_position);
397 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
398 | if (selectionRect.intersects (m_displayInfo[i].m_rect))
399 | m_displayInfo[i].m_isSelected = true;
400 | }
401 | }
402 |
403 | repaint ();
404 | }
405 | else if (m_moveInfo.m_action == MoveComponent) {
406 | int dx = event->x () - m_moveInfo.m_startPosition.x ();
407 | int dy = event->y () - m_moveInfo.m_startPosition.y ();
408 |
409 | if (dx == dy && dy == 0) {
410 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
411 | if (m_displayInfo[i].m_id == m_moveInfo.m_elementId) {
412 | m_displayInfo[i].m_isSelected = true;
413 | repaint ();
414 | break;
415 | }
416 | }
417 | }
418 |
419 | }
420 | exit: m_moveInfo.m_action = None;
421 | m_moveInfo.m_elementId = -1;
422 | m_moveInfo.m_padId = -1;
423 | m_moveInfo.m_startPosition = QPoint ();
424 | m_moveInfo.m_position = QPoint ();
425 | repaint ();
426 | }
427 |
428 | void
429 | GraphDisplay::mouseMoveEvent (QMouseEvent *event)
430 | {
431 | if (m_moveInfo.m_action == MoveComponent) {
432 | int dx = event->x () - m_moveInfo.m_position.x ();
433 | int dy = event->y () - m_moveInfo.m_position.y ();
434 |
435 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
436 | if (m_displayInfo[i].m_id == m_moveInfo.m_elementId) {
437 | QRect newRect = m_displayInfo[i].m_rect;
438 | newRect.adjust (dx, dy, dx, dy);
439 | if (contentsRect ().contains (newRect))
440 | m_displayInfo[i].m_rect = newRect;
441 | break;
442 | }
443 | }
444 | }
445 |
446 | if (m_moveInfo.m_action != None) {
447 | m_moveInfo.m_position = event->pos ();
448 | repaint ();
449 | }
450 | else {
451 | std::size_t elementId, padId;
452 | getIdByPosition (event->pos (), elementId, padId);
453 | if (padId != ((size_t) -1)) {
454 | ElementInfo* element = getElement (elementId);
455 | PadInfo* pad = getPad (elementId, padId);
456 | QString caps = m_pGraph->getPadCaps (element, pad, PAD_CAPS_ALL, true);
457 | setToolTip (caps);
458 | }
459 | else
460 | setToolTip ("");
461 | }
462 | }
463 |
464 | void
465 | GraphDisplay::keyPressEvent (QKeyEvent* event)
466 | {
467 | if (event->key () == Qt::Key_Delete)
468 | removeSelected ();
469 |
470 | return QWidget::keyPressEvent (event);
471 | }
472 |
473 | void
474 | GraphDisplay::showContextMenu (QMouseEvent *event)
475 | {
476 | QMenu menu;
477 |
478 | std::size_t elementId, padId;
479 | getIdByPosition (event->pos (), elementId, padId);
480 |
481 | GstState state;
482 | GstStateChangeReturn res = gst_element_get_state (m_pGraph->m_pGraph, &state,
483 | NULL,
484 | GST_MSECOND);
485 |
486 | bool isActive = false;
487 |
488 | if (res != GST_STATE_CHANGE_SUCCESS || state == GST_STATE_PAUSED
489 | || state == GST_STATE_PLAYING)
490 | isActive = true;
491 |
492 | int selectedCount = 0;
493 | for (std::size_t i = 0; i < m_displayInfo.size (); i++)
494 | if (m_displayInfo[i].m_isSelected)
495 | selectedCount++;
496 |
497 | if (selectedCount > 1) {
498 | CustomMenuAction *pact = new CustomMenuAction ("Remove selected", &menu);
499 | menu.addAction (pact);
500 | if (isActive)
501 | pact->setDisabled (true);
502 |
503 | }
504 | else if (padId != ((size_t) -1)) {
505 | menu.addAction (new CustomMenuAction ("Render", &menu));
506 | menu.addAction (new CustomMenuAction ("Render anyway", &menu));
507 | menu.addAction (new CustomMenuAction ("Pad properties", &menu));
508 | menu.addAction (new CustomMenuAction ("typefind", "ElementName", &menu));
509 | }
510 | else if (elementId != ((size_t) -1)) {
511 | menu.addAction (new CustomMenuAction ("Element properties", &menu));
512 | QAction *pact = new CustomMenuAction ("Remove", &menu);
513 | menu.addAction (pact);
514 |
515 | if (isActive)
516 | pact->setDisabled (true);
517 |
518 | menu.addAction (new CustomMenuAction ("Request pad...", &menu));
519 | }
520 | else {
521 | for (std::size_t i = 0; i < m_info.size (); i++) {
522 | for (std::size_t j = 0; j < m_info[i].m_connections.size (); j++) {
523 |
524 | QPoint point = getPadPosition (m_info[i].m_id,
525 | m_info[i].m_pads[j].m_id);
526 |
527 | double x1, y1;
528 | x1 = point.x ();
529 | y1 = point.y ();
530 |
531 | if (m_info[i].m_connections[j].m_elementId != ((size_t) -1)
532 | && m_info[i].m_connections[j].m_padId != ((size_t) -1)) {
533 | point = getPadPosition (m_info[i].m_connections[j].m_elementId,
534 | m_info[i].m_connections[j].m_padId);
535 | double x2, y2;
536 |
537 | x2 = point.x ();
538 | y2 = point.y ();
539 |
540 | double dy = y2 - y1;
541 | double dx = x2 - x1;
542 |
543 | double x0 = event->pos ().x ();
544 | double y0 = event->pos ().y ();
545 |
546 | double distance = std::abs (
547 | (int) (dy * x0 - dx * y0 + x2 * y1 - y2 * x1));
548 | distance = distance / sqrt (dy * dy + dx * dx);
549 |
550 | if (distance < 5) {
551 | elementId = m_info[i].m_id;
552 | padId = m_info[i].m_pads[j].m_id;
553 |
554 | QAction *pact = new CustomMenuAction ("Disconnect", &menu);
555 | menu.addAction (pact);
556 |
557 | if (isActive)
558 | pact->setDisabled (true);
559 | break;
560 | }
561 | }
562 | }
563 | if (!menu.isEmpty ())
564 | break;
565 | }
566 | if (menu.isEmpty ()) {
567 | menu.addAction (new CustomMenuAction ("Add plugin", &menu));
568 | menu.addAction (new CustomMenuAction ("Clear graph", &menu));
569 | }
570 | }
571 |
572 | if (!menu.isEmpty ()) {
573 | CustomMenuAction *pact = (CustomMenuAction*) menu.exec (
574 | event->globalPos ());
575 | if (pact) {
576 | if (pact->getName () == "Remove")
577 | removePlugin (elementId);
578 | else if (pact->getName () == "Element properties")
579 | showElementProperties (elementId);
580 | else if (pact->getName () == "Pad properties")
581 | showPadProperties (elementId, padId);
582 | else if (pact->getName () == "Render")
583 | renderPad (elementId, padId, true);
584 | else if (pact->getName () == "Render anyway")
585 | renderPad (elementId, padId, false);
586 | else if (pact->getName () == "Disconnect")
587 | disconnect (elementId, padId);
588 | else if (pact->getName () == "Request pad...")
589 | requestPad (elementId);
590 | else if (pact->getName () == "Remove selected")
591 | removeSelected ();
592 | else if (pact->getName () == "ElementName")
593 | connectPlugin (elementId, pact->text ());
594 | else if (pact->getName () == "Add plugin")
595 | addPlugin ();
596 | else if (pact->getName () == "Clear graph")
597 | clearGraph ();
598 | }
599 | }
600 | }
601 |
602 | void
603 | GraphDisplay::removeSelected ()
604 | {
605 | GstState state;
606 | GstStateChangeReturn res = gst_element_get_state (m_pGraph->m_pGraph, &state,
607 | NULL,
608 | GST_MSECOND);
609 |
610 | if (res != GST_STATE_CHANGE_SUCCESS || state == GST_STATE_PAUSED
611 | || state == GST_STATE_PLAYING)
612 | return;
613 |
614 | while (true) {
615 | std::size_t i = 0;
616 | for (; i < m_displayInfo.size (); i++) {
617 | if (m_displayInfo[i].m_isSelected)
618 | break;
619 | }
620 |
621 | if (i != m_displayInfo.size ())
622 | removePlugin (m_displayInfo[i].m_id);
623 | else
624 | break;
625 | }
626 | }
627 |
628 | void
629 | GraphDisplay::addPlugin ()
630 | {
631 | emit signalAddPlugin();
632 | }
633 |
634 | void
635 | GraphDisplay::clearGraph ()
636 | {
637 | emit signalClearGraph();
638 | }
639 |
640 | void
641 | GraphDisplay::removePlugin (std::size_t id)
642 | {
643 | ElementInfo* element = getElement (id);
644 | if (element) {
645 | if (m_pGraph->RemovePlugin (element->m_name.c_str ())) {
646 | std::vector info = m_pGraph->GetInfo ();
647 | update (info);
648 | }
649 | else
650 | QMessageBox::warning (
651 | this,
652 | "Element removing problem",
653 | "Element `" + QString (element->m_name.c_str ())
654 | + "` remowing was FAILED");
655 | }
656 | }
657 |
658 | void
659 | GraphDisplay::connectPlugin (std::size_t elementId, const QString& name)
660 | {
661 | ElementInfo* element = getElement (elementId);
662 | gchar* pluginName = m_pGraph->AddPlugin (name.toStdString ().c_str (), NULL);
663 | m_pGraph->Connect (element->m_name.c_str (), pluginName);
664 | g_free (pluginName);
665 | }
666 |
667 | void
668 | GraphDisplay::showElementProperties (std::size_t id)
669 | {
670 | ElementInfo* element = getElement (id);
671 | if (element) {
672 | ElementProperties *pprops = new ElementProperties (
673 | m_pGraph, element->m_name.c_str ());
674 | pprops->setAttribute (Qt::WA_QuitOnClose, false);
675 | pprops->show ();
676 | }
677 | }
678 |
679 | void
680 | GraphDisplay::showPadProperties (std::size_t elementId, std::size_t padId)
681 | {
682 | ElementInfo* element = getElement (elementId);
683 | PadInfo* pad = getPad (elementId, padId);
684 | if (pad) {
685 | PadProperties *pprops = new PadProperties (m_pGraph,
686 | element->m_name.c_str (),
687 | pad->m_name.c_str ());
688 | pprops->setAttribute (Qt::WA_QuitOnClose, false);
689 | pprops->show ();
690 | }
691 | }
692 |
693 | void
694 | GraphDisplay::renderPad (std::size_t elementId, std::size_t padId, bool capsAny)
695 | {
696 | ElementInfo* element = getElement (elementId);
697 | PadInfo* pad = getPad (elementId, padId);
698 |
699 | if (!element || !pad)
700 | LOG_INFO("element or pad is unreachable");
701 |
702 | PluginsList* pluginList = new PluginsList ();
703 | GList* plugins_list = pluginList->getSortedByRank ();
704 | GList* l;
705 |
706 | for (l = plugins_list; l != NULL; l = l->next) {
707 | Plugin* plugin = (Plugin*) (l->data);
708 | if (m_pGraph->CanConnect (element->m_name.c_str (), pad->m_name.c_str (),
709 | plugin->getName ().toStdString ().c_str (),
710 | capsAny)) {
711 | gchar* pluginName = m_pGraph->AddPlugin (
712 | plugin->getName ().toStdString ().c_str (), NULL);
713 | m_pGraph->Connect (element->m_name.c_str (), pluginName);
714 | g_free (pluginName);
715 | break;
716 | }
717 | }
718 | delete pluginList;
719 | }
720 |
721 | void
722 | GraphDisplay::disconnect (size_t elementId, size_t padId)
723 | {
724 | std::string src, dst, srcPad, dstPad;
725 |
726 | for (std::size_t i = 0; i < m_info.size (); i++) {
727 | if (m_info[i].m_id == elementId) {
728 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
729 | if (m_info[i].m_pads[j].m_id == padId) {
730 | if (m_info[i].m_pads[j].m_type == PadInfo::Out) {
731 | src = m_info[i].m_name;
732 | srcPad = m_info[i].m_pads[j].m_name.c_str ();
733 | elementId = m_info[i].m_connections[j].m_elementId;
734 | padId = m_info[i].m_connections[j].m_padId;
735 | }
736 | else {
737 | dst = m_info[i].m_name;
738 | dstPad = m_info[i].m_pads[j].m_name.c_str ();
739 | elementId = m_info[i].m_connections[j].m_elementId;
740 | padId = m_info[i].m_connections[j].m_padId;
741 | }
742 | break;
743 | }
744 | }
745 |
746 | break;
747 | }
748 | }
749 |
750 | for (std::size_t i = 0; i < m_info.size (); i++) {
751 | if (m_info[i].m_id == elementId) {
752 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
753 | if (m_info[i].m_pads[j].m_id == padId) {
754 | if (m_info[i].m_pads[j].m_type == PadInfo::Out) {
755 | src = m_info[i].m_name;
756 | srcPad = m_info[i].m_pads[j].m_name.c_str ();
757 | }
758 | else {
759 | dst = m_info[i].m_name;
760 | dstPad = m_info[i].m_pads[j].m_name.c_str ();
761 | }
762 | break;
763 | }
764 | }
765 | break;
766 | }
767 | }
768 |
769 | LOG_INFO("Disconnect %s:%s <-> %s,%s", src.c_str (), srcPad.c_str(), dst.c_str (), dstPad.c_str ());
770 |
771 | if (src.empty () || dst.empty () || srcPad.empty () || dstPad.empty ())
772 | return;
773 |
774 | m_pGraph->Disconnect (src.c_str (), srcPad.c_str (), dst.c_str (),
775 | dstPad.c_str ());
776 |
777 | m_info = m_pGraph->GetInfo ();
778 | updateDisplayInfoIds ();
779 | repaint ();
780 | }
781 |
782 | void
783 | GraphDisplay::requestPad (std::size_t elementId)
784 | {
785 | QStringList labels;
786 | labels.push_back ("Template name");
787 | labels.push_back ("Caps");
788 | labels.push_back ("Direction");
789 |
790 | QTableWidget *ptwgt = new QTableWidget ();
791 | ptwgt->setColumnCount (3);
792 | ptwgt->setHorizontalHeaderLabels (labels);
793 | ptwgt->setSelectionBehavior (QAbstractItemView::SelectRows);
794 | ptwgt->setEditTriggers (QAbstractItemView::NoEditTriggers);
795 |
796 | ElementInfo* elementInfo = getElement (elementId);
797 | GstElement *element = NULL;
798 | if (elementInfo)
799 | element = gst_bin_get_by_name (GST_BIN (m_pGraph->m_pGraph),
800 | elementInfo->m_name.c_str ());
801 |
802 | if (!element) {
803 | QMessageBox::warning (this, "Request pad failed",
804 | "Request pad list obtaining was failed");
805 | return;
806 | }
807 |
808 | GstElementClass *klass;
809 | klass = GST_ELEMENT_GET_CLASS (element);
810 |
811 | GList *lst = gst_element_class_get_pad_template_list (klass);
812 |
813 | std::size_t k = 0;
814 | while (lst != NULL) {
815 | GstPadTemplate *templ;
816 | templ = (GstPadTemplate *) lst->data;
817 |
818 | if (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_REQUEST) {
819 | ptwgt->setRowCount (k + 1);
820 | ptwgt->setItem (
821 | k, 0, new QTableWidgetItem (GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)));
822 |
823 | GstCaps *caps = gst_pad_template_get_caps (templ);
824 | gchar *capsStr = gst_caps_to_string (caps);
825 | ptwgt->setItem (k, 1, new QTableWidgetItem (capsStr));
826 | g_free (capsStr);
827 | gst_caps_unref (caps);
828 |
829 | const char *directionSrc = "SRC";
830 | const char *directionSink = "SINK";
831 | const char *directionUnknown = "UNKNOWN";
832 |
833 | QString direction;
834 | switch (GST_PAD_TEMPLATE_DIRECTION (templ)) {
835 | case GST_PAD_UNKNOWN:
836 | direction = directionUnknown;
837 | break;
838 |
839 | case GST_PAD_SRC:
840 | direction = directionSrc;
841 | break;
842 |
843 | case GST_PAD_SINK:
844 | direction = directionSink;
845 | break;
846 | };
847 |
848 | ptwgt->setItem (k, 2, new QTableWidgetItem (direction));
849 | k++;
850 | }
851 |
852 | lst = g_list_next (lst);
853 | }
854 |
855 | qulonglong v ((qulonglong) element);
856 | ptwgt->setProperty ("element", v);
857 |
858 | connect(ptwgt, SIGNAL(cellActivated(int, int)), SLOT(addRequestPad(int, int)));
859 |
860 | ptwgt->setAttribute (Qt::WA_QuitOnClose, false);
861 | ptwgt->show ();
862 | }
863 |
864 | void
865 | GraphDisplay::addRequestPad (int row, int collumn)
866 | {
867 | Q_UNUSED(collumn);
868 | QTableWidget *ptwgt = dynamic_cast (QObject::sender ());
869 |
870 | qulonglong v = ptwgt->property ("element").toULongLong ();
871 | GstElement *element = (GstElement *) v;
872 | GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
873 |
874 | GstPadTemplate *templ = gst_element_class_get_pad_template (
875 | klass, ptwgt->itemAt (row, 0)->text ().toStdString ().c_str ());
876 |
877 | gst_element_request_pad (element, templ, NULL, NULL);
878 |
879 | gst_object_unref (element);
880 | ptwgt->close ();
881 |
882 | std::vector info = m_pGraph->GetInfo ();
883 | update (info);
884 |
885 | }
886 |
887 | void
888 | GraphDisplay::getIdByPosition (const QPoint &pos, std::size_t &elementId,
889 | std::size_t &padId)
890 | {
891 | std::size_t i = 0;
892 | elementId = padId = -1;
893 | for (; i < m_displayInfo.size (); i++) {
894 | if (elementId != ((size_t) -1))
895 | break;
896 |
897 | QRect rect (m_displayInfo[i].m_rect.x () - 8,
898 | m_displayInfo[i].m_rect.y () - 6,
899 | m_displayInfo[i].m_rect.width () + 16,
900 | m_displayInfo[i].m_rect.height () + 12);
901 | if (rect.contains (pos)) {
902 | std::size_t j = 0;
903 | for (; j < m_info[i].m_pads.size (); j++) {
904 | QPoint point = getPadPosition (m_displayInfo[i].m_id,
905 | m_info[i].m_pads[j].m_id);
906 |
907 | int xPos, yPos;
908 | xPos = point.x ();
909 | yPos = point.y ();
910 |
911 | xPos -= PAD_SIZE_ACTION / 2;
912 | yPos -= PAD_SIZE_ACTION / 2;
913 |
914 | QRect rect (xPos, yPos, PAD_SIZE_ACTION, PAD_SIZE_ACTION);
915 | if (rect.contains (pos)) {
916 | padId = m_info[i].m_pads[j].m_id;
917 | elementId = m_displayInfo[i].m_id;
918 | break;
919 | }
920 | }
921 |
922 | if (j == m_info[i].m_pads.size ()) {
923 | if (m_displayInfo[i].m_rect.contains (pos))
924 | elementId = m_displayInfo[i].m_id;
925 | }
926 | }
927 | }
928 | }
929 |
930 | QPoint
931 | GraphDisplay::getPadPosition (std::size_t elementId, std::size_t padId)
932 | {
933 | QPoint res;
934 | if (elementId == ((size_t) -1) || padId == ((size_t) -1))
935 | return res;
936 |
937 | for (std::size_t i = 0; i < m_displayInfo.size (); i++) {
938 | if (m_displayInfo[i].m_id == elementId) {
939 | int numInPads, numOutPads;
940 | numInPads = numOutPads = 0;
941 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
942 | if (m_info[i].m_pads[j].m_type == PadInfo::Out)
943 | numOutPads++;
944 | else if (m_info[i].m_pads[j].m_type == PadInfo::In)
945 | numInPads++;
946 | }
947 |
948 | int inDelta, outDelta, inPos, outPos;
949 |
950 | inDelta = m_displayInfo[i].m_rect.height () / (numInPads + 1);
951 | outDelta = m_displayInfo[i].m_rect.height () / (numOutPads + 1);
952 |
953 | inPos = inDelta;
954 | outPos = outDelta;
955 | for (std::size_t j = 0; j < m_info[i].m_pads.size (); j++) {
956 | int xPos, yPos;
957 | yPos = m_displayInfo[i].m_rect.topRight ().y ();
958 |
959 | if (m_info[i].m_pads[j].m_type == PadInfo::Out) {
960 | xPos = m_displayInfo[i].m_rect.topRight ().x ();
961 | yPos += outPos;
962 | outPos += outDelta;
963 | }
964 | else if (m_info[i].m_pads[j].m_type == PadInfo::In) {
965 | xPos = m_displayInfo[i].m_rect.topLeft ().x ();
966 | yPos += inPos;
967 | inPos += inDelta;
968 | }
969 |
970 | if (m_info[i].m_pads[j].m_id == padId) {
971 | res = QPoint (xPos, yPos);
972 | break;
973 | }
974 | }
975 |
976 | break;
977 | }
978 | }
979 |
980 | return res;
981 | }
982 |
--------------------------------------------------------------------------------
/src/GraphDisplay.h:
--------------------------------------------------------------------------------
1 | #ifndef GRAPH_DISPLAY_H_
2 | #define GRAPH_DISPLAY_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #include "GraphManager.h"
11 | #include
12 |
13 | class GraphDisplay: public QWidget
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | GraphDisplay(QWidget *parent=0, Qt::WindowFlags f=0);
19 | void update(const std::vector &info);
20 | void paintEvent(QPaintEvent *event);
21 | void mousePressEvent(QMouseEvent *event);
22 | void mouseReleaseEvent(QMouseEvent *event);
23 | void mouseMoveEvent(QMouseEvent *event);
24 |
25 | void keyPressEvent(QKeyEvent* event);
26 |
27 | QSharedPointer m_pGraph;
28 |
29 | private slots:
30 | void addRequestPad(int row, int collumn);
31 |
32 | signals:
33 | void signalAddPlugin();
34 | void signalClearGraph();
35 |
36 | private:
37 |
38 | enum MoveAction
39 | {
40 | None = 0,
41 | MoveComponent,
42 | MakeConnect,
43 | Select
44 | };
45 |
46 | struct MoveInfo
47 | {
48 | MoveInfo(): m_action(None)
49 | {
50 | }
51 |
52 | MoveAction m_action;
53 | size_t m_elementId;
54 | size_t m_padId;
55 | QPoint m_position;
56 | QPoint m_startPosition;
57 | };
58 |
59 | struct ElementDisplayInfo
60 | {
61 | QRect m_rect;
62 | size_t m_id;
63 | std::string m_name;
64 | bool m_isSelected;
65 | };
66 |
67 | void calculatePositions();
68 | void updateDisplayInfoIds();
69 | ElementDisplayInfo calculateOnePosition(const ElementInfo &info);
70 | void showContextMenu(QMouseEvent *event);
71 | void showElementProperties(std::size_t id);
72 | void showPadProperties(std::size_t elementId, std::size_t padId);
73 | void renderPad(std::size_t elementId, std::size_t padId, bool capsAny);
74 | void removePlugin(std::size_t id);
75 | void removeSelected();
76 | void getIdByPosition(const QPoint &pos, std::size_t &elementId, std::size_t &padId);
77 | QPoint getPadPosition(std::size_t elementId, std::size_t padId);
78 | void disconnect(std::size_t elementId, std::size_t padId);
79 | void requestPad(std::size_t elementId);
80 | void connectPlugin(std::size_t elementId, const QString& destElementName);
81 | void addPlugin();
82 | void clearGraph();
83 |
84 | ElementInfo* getElement(std::size_t elementId);
85 | PadInfo* getPad(std::size_t elementId, std::size_t padId);
86 |
87 | std::vector m_info;
88 | std::vector m_displayInfo;
89 |
90 | MoveInfo m_moveInfo;
91 | };
92 |
93 | #endif
94 |
--------------------------------------------------------------------------------
/src/GraphManager.cpp:
--------------------------------------------------------------------------------
1 | #include "GraphManager.h"
2 | #include "PluginsList.h"
3 |
4 | #include "MainWindow.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "CustomSettings.h"
11 |
12 | GST_DEBUG_CATEGORY_STATIC(pipeviz_debug);
13 | #define GST_CAT_DEFAULT pipeviz_debug
14 |
15 | #define MAX_STR_CAPS_SIZE 150
16 | gchar*
17 | get_str_caps_limited (gchar* str)
18 | {
19 | gchar* result;
20 | if (strlen (str) > MAX_STR_CAPS_SIZE) {
21 | result = g_strndup (str, MAX_STR_CAPS_SIZE);
22 | for (size_t i = strlen (result) - 1; i > strlen (result) - 4; i--)
23 | result[i] = '.';
24 | }
25 | else
26 | result = g_strdup (str);
27 | return result;
28 | }
29 |
30 | static void
31 | typefind_have_type_callback (GstElement * typefind, guint probability,
32 | GstCaps * caps, GraphManager * thiz)
33 | {
34 | Q_UNUSED(typefind);
35 | gchar *caps_description = gst_caps_to_string (caps);
36 | GST_DEBUG_OBJECT(thiz, "Found caps %s with probability %d",caps_description, probability);
37 | g_free (caps_description);
38 | thiz->Pause ();
39 | }
40 |
41 | GraphManager::GraphManager ()
42 | {
43 | m_pGraph = gst_pipeline_new ("pipeline");
44 | GST_DEBUG_CATEGORY_INIT(pipeviz_debug, "pipeviz", 0, "Pipeline vizualizer");
45 |
46 | GST_WARNING("init");
47 | }
48 |
49 | GraphManager::~GraphManager ()
50 | {
51 | }
52 |
53 | QString
54 | GraphManager::getPadCaps (ElementInfo* elementInfo, PadInfo* padInfo,
55 | ePadCapsSubset subset, bool afTruncated)
56 | {
57 | QString padCaps = "";
58 | if (!elementInfo || !padInfo)
59 | return padCaps;
60 |
61 | GstElement *element = gst_bin_get_by_name (GST_BIN (m_pGraph),
62 | elementInfo->m_name.c_str ());
63 |
64 | if (!element)
65 | return padCaps;
66 | GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (element),
67 | padInfo->m_name.c_str ());
68 | if (!pad) {
69 | gst_object_unref (element);
70 | return padCaps;
71 | }
72 | GstCaps *caps;
73 | switch (subset) {
74 | case PAD_CAPS_ALLOWED:
75 | caps = gst_pad_get_allowed_caps (pad);
76 | break;
77 | case PAD_CAPS_NEGOCIATED:
78 | #if GST_VERSION_MAJOR >= 1
79 | caps = gst_pad_get_current_caps(pad);
80 | #else
81 | caps = gst_pad_get_negotiated_caps (pad);
82 | #endif
83 | break;
84 | case PAD_CAPS_ALL:
85 | default:
86 | #if GST_VERSION_MAJOR >= 1
87 | caps = gst_pad_query_caps(pad, NULL);
88 | #else
89 | caps = gst_pad_get_caps (pad);
90 | #endif
91 | }
92 | #if GST_VERSION_MAJOR >= 1
93 | caps = gst_pad_query_caps(pad, NULL);
94 | #else
95 | caps = gst_pad_get_caps (pad);
96 | #endif
97 | if (caps) {
98 | gchar* str = gst_caps_to_string (caps);
99 | if (afTruncated) {
100 | gchar* str_limited = get_str_caps_limited (str);
101 | g_free (str);
102 | padCaps = str_limited;
103 | g_free (str_limited);
104 | }
105 | else {
106 | padCaps = str;
107 | g_free (str);
108 | }
109 |
110 | }
111 |
112 | gst_object_unref (element);
113 | gst_object_unref (pad);
114 | return padCaps;
115 | }
116 |
117 | gchar*
118 | GraphManager::AddPlugin (const char *plugin, const char *name)
119 | {
120 | GstElement *pel = gst_element_factory_make (plugin, name);
121 | if (!pel)
122 | return NULL;
123 |
124 | if (GST_IS_URI_HANDLER (pel)) {
125 | static const gchar * const *protocols;
126 | protocols = gst_uri_handler_get_protocols (GST_URI_HANDLER (pel));
127 |
128 | bool isFile = false;
129 |
130 | for (std::size_t i = 0; protocols[i] != NULL; i++) {
131 | if (strcmp ("file", protocols[i]) == 0) {
132 | isFile = true;
133 | break;
134 | }
135 | }
136 |
137 | if (isFile) {
138 | QString path;
139 | QString dir = CustomSettings::lastIODirectory ();
140 |
141 | if (gst_uri_handler_get_uri_type (GST_URI_HANDLER (pel)) == GST_URI_SRC)
142 | path = QFileDialog::getOpenFileName (NULL, "Open Media Source File...",
143 | dir);
144 | else
145 | path = QFileDialog::getSaveFileName (NULL, "Open Sink File...", dir);
146 |
147 | if (!path.isEmpty ()) {
148 | gchar *uri = gst_filename_to_uri (path.toStdString ().c_str (),
149 | NULL);
150 | if (uri) {
151 | GST_DEBUG("Set uri: %s", uri);
152 | #if GST_VERSION_MAJOR >= 1
153 | gst_uri_handler_set_uri(GST_URI_HANDLER(pel), uri, NULL);
154 | #else
155 | gst_uri_handler_set_uri (GST_URI_HANDLER (pel), uri);
156 | #endif
157 | g_free (uri);
158 |
159 | QString dir = QFileInfo (path).absoluteDir ().absolutePath ();
160 | CustomSettings::saveLastIODirectory (dir);
161 | }
162 | }
163 | }
164 | else {
165 | QString uri = QInputDialog::getText (NULL, "Uri...", "Uri:");
166 |
167 | if (!uri.isEmpty ()) {
168 | GST_DEBUG("Set uri: %s", uri.toStdString ().c_str ());
169 | #if GST_VERSION_MAJOR >= 1
170 | gst_uri_handler_set_uri(GST_URI_HANDLER(pel), uri.toStdString().c_str(), NULL);
171 | #else
172 | gst_uri_handler_set_uri (GST_URI_HANDLER (pel),
173 | uri.toStdString ().c_str ());
174 | #endif
175 | }
176 | }
177 | }
178 |
179 | bool res = gst_bin_add (GST_BIN (m_pGraph), pel);
180 | if (res)
181 | gst_element_sync_state_with_parent (pel);
182 | else {
183 | gst_object_unref (pel);
184 | return NULL;
185 | }
186 |
187 | return gst_element_get_name (pel);
188 | }
189 |
190 | bool
191 | GraphManager::RemovePlugin (const char *name)
192 | {
193 | GstElement *element = gst_bin_get_by_name (GST_BIN (m_pGraph), name);
194 |
195 | if (!element)
196 | return false;
197 |
198 | bool res = gst_bin_remove (GST_BIN (m_pGraph), element);
199 | gst_object_unref (element);
200 |
201 | return res;
202 | }
203 |
204 | bool
205 | GraphManager::OpenUri (const char *uri, const char *name)
206 | {
207 | #if GST_VERSION_MAJOR >= 1
208 | GstElement *element = gst_element_make_from_uri(GST_URI_SRC, uri, name, NULL);
209 | #else
210 | GstElement *element = gst_element_make_from_uri (GST_URI_SRC, uri, name);
211 | #endif
212 | if (!element)
213 | return false;
214 |
215 | bool res = gst_bin_add (GST_BIN (m_pGraph), element);
216 | if (res)
217 | gst_element_sync_state_with_parent (element);
218 |
219 | return res;
220 | }
221 |
222 | bool
223 | GraphManager::Connect (const char *srcElement, const char *srcPad,
224 | const char *dstElement, const char *dstPad)
225 | {
226 | GstElement *src = gst_bin_get_by_name (GST_BIN (m_pGraph), srcElement);
227 | GstElement *dst = gst_bin_get_by_name (GST_BIN (m_pGraph), dstElement);
228 |
229 | bool res = gst_element_link_pads (src, srcPad, dst, dstPad);
230 |
231 | gboolean seekRes = gst_element_seek_simple (m_pGraph, GST_FORMAT_TIME,
232 | GST_SEEK_FLAG_FLUSH, 0);
233 | Q_UNUSED(seekRes);
234 | gst_object_unref (src);
235 | gst_object_unref (dst);
236 |
237 | return res;
238 | }
239 |
240 | bool
241 | GraphManager::Connect (const char *srcElement, const char *dstElement)
242 | {
243 |
244 | GstElement *src = gst_bin_get_by_name (GST_BIN (m_pGraph), srcElement);
245 | GstElement *dst = gst_bin_get_by_name (GST_BIN (m_pGraph), dstElement);
246 |
247 | bool res = gst_element_link (src, dst);
248 |
249 | gboolean seekRes = gst_element_seek_simple (m_pGraph, GST_FORMAT_TIME,
250 | GST_SEEK_FLAG_FLUSH, 0);
251 | Q_UNUSED(seekRes);
252 | /* add a callback to handle have-type signal */
253 | if (g_str_has_prefix (dstElement, "typefindelement")) {
254 | g_signal_connect (dst, "have-type",
255 | G_CALLBACK (typefind_have_type_callback), this);
256 | Play ();
257 | }
258 |
259 | gst_object_unref (src);
260 | gst_object_unref (dst);
261 |
262 | return res;
263 | }
264 |
265 | bool
266 | GraphManager::Disconnect (const char *srcElement, const char *srcPad,
267 | const char *dstElement, const char *dstPad)
268 | {
269 | GstElement *src = gst_bin_get_by_name (GST_BIN (m_pGraph), srcElement);
270 | GstElement *dst = gst_bin_get_by_name (GST_BIN (m_pGraph), dstElement);
271 |
272 | gst_element_unlink_pads (src, srcPad, dst, dstPad);
273 |
274 | gst_object_unref (src);
275 | gst_object_unref (dst);
276 |
277 | return true;
278 | }
279 |
280 | std::vector
281 | GraphManager::GetInfo ()
282 | {
283 | std::vector res;
284 |
285 | GstIterator *iter;
286 | iter = gst_bin_iterate_elements (GST_BIN (m_pGraph));
287 | GstElement* element = NULL;
288 | bool done = false;
289 | size_t id = 0;
290 | while (!done) {
291 | #if GST_VERSION_MAJOR >= 1
292 | GValue value = G_VALUE_INIT;
293 | switch (gst_iterator_next (iter, &value))
294 | {
295 | case GST_ITERATOR_OK:
296 | {
297 | element = GST_ELEMENT(g_value_get_object(&value));
298 | #else
299 | switch (gst_iterator_next (iter, (gpointer *) &element)) {
300 | case GST_ITERATOR_OK: {
301 | #endif
302 | ElementInfo elementInfo;
303 | elementInfo.m_id = id;
304 | id++;
305 |
306 | gchar *name = gst_element_get_name (element);
307 | elementInfo.m_name = name;
308 | g_free (name);
309 |
310 | GstElementFactory *pfactory = gst_element_get_factory (element);
311 |
312 | elementInfo.m_pluginName = gst_plugin_feature_get_name (
313 | GST_PLUGIN_FEATURE (pfactory));
314 |
315 | GstIterator *padItr = gst_element_iterate_pads (element);
316 | bool padDone = FALSE;
317 | std::size_t padId = 0;
318 | GstPad *pad;
319 | while (!padDone) {
320 | #if GST_VERSION_MAJOR >= 1
321 | GValue padVal = G_VALUE_INIT;
322 | switch (gst_iterator_next (padItr, &padVal))
323 | {
324 | case GST_ITERATOR_OK:
325 | {
326 | pad = GST_PAD(g_value_get_object(&padVal));
327 | #else
328 | switch (gst_iterator_next (padItr, (gpointer *) &pad)) {
329 | case GST_ITERATOR_OK: {
330 | #endif
331 | PadInfo padInfo;
332 | padInfo.m_id = padId;
333 |
334 | gchar *pad_name = gst_pad_get_name (pad);
335 | padInfo.m_name = pad_name;
336 | g_free (pad_name);
337 |
338 | GstPadDirection direction = gst_pad_get_direction (pad);
339 | if (direction == GST_PAD_SRC)
340 | padInfo.m_type = PadInfo::Out;
341 | else if (direction == GST_PAD_SINK)
342 | padInfo.m_type = PadInfo::In;
343 | else
344 | padInfo.m_type = PadInfo::None;
345 |
346 | elementInfo.m_pads.push_back (padInfo);
347 | #if GST_VERSION_MAJOR >= 1
348 | g_value_reset (&padVal);
349 | #endif
350 | break;
351 | }
352 | case GST_ITERATOR_RESYNC:
353 | case GST_ITERATOR_ERROR:
354 | case GST_ITERATOR_DONE:
355 | padDone = TRUE;
356 | break;
357 | };
358 | padId++;
359 | }
360 | #if GST_VERSION_MAJOR >= 1
361 | g_value_reset (&value);
362 | #endif
363 | res.push_back (elementInfo);
364 | break;
365 | }
366 | case GST_ITERATOR_DONE:
367 | case GST_ITERATOR_RESYNC:
368 | case GST_ITERATOR_ERROR: {
369 | done = true;
370 | break;
371 | }
372 | };
373 | }
374 |
375 | gst_iterator_free (iter);
376 |
377 | for (std::size_t i = 0; i < res.size (); i++) {
378 | res[i].m_connections.resize (res[i].m_pads.size ());
379 |
380 | GstElement *element = gst_bin_get_by_name (GST_BIN (m_pGraph),
381 | res[i].m_name.c_str ());
382 |
383 | for (std::size_t j = 0; j < res[i].m_pads.size (); j++) {
384 | res[i].m_connections[j].m_elementId = -1;
385 | res[i].m_connections[j].m_padId = -1;
386 |
387 | GstPad *pad = gst_element_get_static_pad (
388 | element, res[i].m_pads[j].m_name.c_str ());
389 | GstPad *peerPad = gst_pad_get_peer (pad);
390 |
391 | if (peerPad) {
392 | GstElement *peerElement = GST_ELEMENT (gst_pad_get_parent (peerPad));
393 |
394 | gchar *peerName = gst_element_get_name (peerElement);
395 | gchar *peerPadName = gst_pad_get_name (peerPad);
396 |
397 | for (std::size_t k = 0; k < res.size (); k++) {
398 | if (res[k].m_name == peerName) {
399 | for (std::size_t l = 0; l < res[k].m_pads.size (); l++) {
400 | if (res[k].m_pads[l].m_name == peerPadName) {
401 | res[i].m_connections[j].m_elementId = res[k].m_id;
402 | res[i].m_connections[j].m_padId = res[k].m_pads[l].m_id;
403 | break;
404 | }
405 | }
406 | }
407 | }
408 |
409 | g_free (peerName);
410 | g_free (peerPadName);
411 |
412 | gst_object_unref (peerPad);
413 | gst_object_unref (peerElement);
414 | }
415 |
416 | gst_object_unref (pad);
417 | }
418 | gst_object_unref (element);
419 |
420 | }
421 |
422 | return res;
423 | }
424 |
425 | bool
426 | GraphManager::Play ()
427 | {
428 | GstStateChangeReturn res;
429 | gst_element_set_state (m_pGraph, GST_STATE_PLAYING);
430 |
431 | GstState state;
432 | res = gst_element_get_state (m_pGraph, &state, NULL, GST_SECOND);
433 |
434 | if (res != GST_STATE_CHANGE_SUCCESS) {
435 | gst_element_abort_state (m_pGraph);
436 | GST_WARNING("state changing to Play was FAILED");
437 | }
438 |
439 | return state == GST_STATE_PLAYING;
440 | }
441 |
442 | bool
443 | GraphManager::Pause ()
444 | {
445 | GstStateChangeReturn res;
446 |
447 | GstState state;
448 | gst_element_set_state (m_pGraph, GST_STATE_PAUSED);
449 | res = gst_element_get_state (m_pGraph, &state, NULL, GST_SECOND);
450 | if (res != GST_STATE_CHANGE_SUCCESS) {
451 | gst_element_abort_state (m_pGraph);
452 | GST_WARNING("state changing to Pause was FAILED");
453 | }
454 |
455 | return state == GST_STATE_PAUSED;
456 | }
457 |
458 | bool
459 | GraphManager::Stop ()
460 | {
461 | GstStateChangeReturn res = gst_element_set_state (m_pGraph, GST_STATE_READY);
462 | return res == GST_STATE_CHANGE_SUCCESS;
463 | }
464 |
465 | double
466 | GraphManager::GetPosition ()
467 | {
468 | gint64 current, duration;
469 | GstFormat fmt = GST_FORMAT_TIME;
470 | #if GST_VERSION_MAJOR >= 1
471 | if(!gst_element_query_position(m_pGraph, fmt, ¤t))
472 | return 0;
473 | #else
474 | if (!gst_element_query_position (m_pGraph, &fmt, ¤t))
475 | return 0;
476 | #endif
477 |
478 | #if GST_VERSION_MAJOR >= 1
479 | if(!gst_element_query_duration(m_pGraph, fmt, &duration))
480 | return 0;
481 | #else
482 | if (!gst_element_query_duration (m_pGraph, &fmt, &duration))
483 | return 0;
484 | #endif
485 |
486 | if (duration < 0 || current < 0)
487 | return 0;
488 |
489 | return (double) current / duration;
490 | }
491 |
492 | bool
493 | GraphManager::SetPosition (double pos)
494 | {
495 | GstQuery *query = gst_query_new_seeking (GST_FORMAT_TIME);
496 | GstFormat fmt = GST_FORMAT_TIME;
497 | if (!query)
498 | return false;
499 |
500 | if (!gst_element_query (m_pGraph, query))
501 | return false;
502 |
503 | gboolean seekable;
504 | gst_query_parse_seeking (query, NULL, &seekable, NULL, NULL);
505 |
506 | gst_query_unref (query);
507 |
508 | if (!seekable)
509 | return false;
510 |
511 | gint64 duration;
512 |
513 | #if GST_VERSION_MAJOR >= 1
514 | if(!gst_element_query_duration(m_pGraph, fmt, &duration))
515 | return 0;
516 | #else
517 | if (!gst_element_query_duration (m_pGraph, &fmt, &duration))
518 | return 0;
519 | #endif
520 |
521 | if (duration < 0)
522 | return 0;
523 |
524 | gboolean seekRes = gst_element_seek_simple (m_pGraph, GST_FORMAT_TIME,
525 | GST_SEEK_FLAG_FLUSH,
526 | duration * pos);
527 |
528 | return seekRes;
529 | }
530 |
531 | bool
532 | GraphManager::CanConnect (const char *srcName, const char *srcPadName,
533 | const char *destName, bool noANY)
534 | {
535 | bool ret = false;
536 | bool added = false;
537 | GstElement *dest = NULL;
538 | GstElement *src = NULL;
539 | GstPad* srcPad = NULL;
540 | GstCaps* srcCaps = NULL;
541 | GstElementFactory *destFactory = NULL;
542 |
543 | src = gst_bin_get_by_name (GST_BIN (m_pGraph), srcName);
544 | if (!src) {
545 | GST_DEBUG("Unable to get the src element: %s",srcName);
546 | goto done;
547 | }
548 |
549 | srcPad = gst_element_get_static_pad (src, srcPadName);
550 | if (!srcPad) {
551 | GST_DEBUG("Unable to get the src pad: %s",srcPadName);
552 | goto done;
553 | }
554 |
555 | srcCaps = gst_pad_get_current_caps (srcPad);
556 | if (!srcCaps) {
557 | GST_DEBUG("Unable to get the current caps for pad: %s",srcPadName);
558 | srcCaps = gst_pad_get_pad_template_caps (srcPad);
559 | if (!srcCaps) {
560 | GST_DEBUG("Unable to get the template caps for pad: %s",srcPadName);
561 | goto done;
562 | }
563 | }
564 |
565 | dest = gst_element_factory_make (destName, NULL);
566 | if (!dest) {
567 | GST_DEBUG("Unable to get the dest element: %s",destName);
568 | goto done;
569 | }
570 |
571 | destFactory = gst_element_get_factory (dest);
572 | if (!destFactory) {
573 | GST_DEBUG("Unable to get the factory for dest element %s",destName);
574 | goto done;
575 | }
576 | if (noANY && gst_element_factory_can_sink_any_caps (destFactory, srcCaps)) {
577 | GST_DEBUG("The dest element %s can sink any caps",destName);
578 | goto done;
579 | }
580 |
581 | if (!gst_element_factory_can_sink_all_caps (destFactory, srcCaps)) {
582 | gchar* caps_string = gst_caps_to_string (srcCaps);
583 | GST_DEBUG("The dest element %s can not sink this caps %s",destName, caps_string);
584 | g_free (caps_string);
585 | goto done;
586 | }
587 |
588 | added = gst_bin_add (GST_BIN (m_pGraph), dest);
589 | if (!added) {
590 | GST_DEBUG("Unable to add element %s to the bin", destName);
591 | goto done;
592 | }
593 |
594 | ret = gst_element_link (src, dest);
595 | if (ret) {
596 | GST_INFO("Can link elements src %s with dest %s", GST_OBJECT_NAME (src), GST_OBJECT_NAME (dest));
597 | gst_element_unlink (src, dest);
598 | }
599 |
600 | done: if (added) {
601 | gst_bin_remove (GST_BIN (m_pGraph), dest);
602 | dest = NULL;
603 | }
604 | if (src)
605 | gst_object_unref (src);
606 | if (srcPad)
607 | gst_object_unref (srcPad);
608 | if (dest)
609 | gst_object_unref (dest);
610 | return ret;
611 | }
612 |
--------------------------------------------------------------------------------
/src/GraphManager.h:
--------------------------------------------------------------------------------
1 | #ifndef GRAPH_MANAGER_H_
2 | #define GRAPH_MANAGER_H_
3 |
4 | #include "Logger.h"
5 |
6 | #include
7 |
8 | #include
9 | #include
10 |
11 | class QString;
12 | class PluginsList;
13 |
14 | enum ePadCapsSubset {
15 | PAD_CAPS_ALLOWED = 0,
16 | PAD_CAPS_NEGOCIATED,
17 | PAD_CAPS_ALL
18 | };
19 |
20 | struct PadInfo
21 | {
22 | public:
23 | enum PadType
24 | {
25 | None,
26 | Out,
27 | In
28 | };
29 |
30 | size_t m_id;
31 | PadType m_type;
32 | std::string m_name;
33 |
34 |
35 | bool operator == (const PadInfo &obj) const
36 | {
37 | if(this == &obj)
38 | return true;
39 |
40 | if(m_id != obj.m_id)
41 | return false;
42 |
43 | if(m_type != obj.m_type)
44 | return false;
45 |
46 | if(m_name != obj.m_name)
47 | return false;
48 |
49 | return true;
50 | }
51 | };
52 |
53 | struct ElementInfo
54 | {
55 | struct Connection
56 | {
57 | size_t m_padId;
58 | size_t m_elementId;
59 |
60 | bool operator == (const Connection &obj) const
61 | {
62 | if(this == &obj)
63 | return true;
64 |
65 | if(m_padId != obj.m_padId)
66 | return false;
67 |
68 | if(m_elementId != obj.m_elementId)
69 | return false;
70 |
71 | return true;
72 | }
73 | };
74 |
75 |
76 | size_t m_id;
77 | std::string m_name;
78 | std::string m_pluginName;
79 | std::vector m_pads;
80 | std::vector m_connections;
81 | };
82 |
83 |
84 | class GraphManager
85 | {
86 |
87 | public:
88 | GraphManager();
89 | ~GraphManager();
90 |
91 | gchar* AddPlugin(const char *plugin, const char *name);
92 | bool RemovePlugin(const char *name);
93 | bool Connect(const char *srcElement, const char *srcPad,
94 | const char *dstElement, const char *dstPad);
95 | bool Connect(const char *srcElement, const char *dstElement);
96 | bool Disconnect(const char *srcElement, const char *srcPad,
97 | const char *dstElement, const char *dstPad);
98 | std::vector GetInfo();
99 |
100 | bool OpenUri(const char *uri, const char *name);
101 |
102 | double GetPosition();
103 | bool SetPosition(double);
104 |
105 | bool CanConnect(const char *srcName,const char *srcPadName, const char *destName, bool noANY = true);
106 |
107 |
108 | bool Play();
109 | bool Pause();
110 | bool Stop();
111 |
112 | QString getPadCaps(ElementInfo* elementInfo, PadInfo* padInfo, ePadCapsSubset subset, bool afTruncated = false);
113 |
114 | GstElement *m_pGraph;
115 | };
116 |
117 | #endif
118 |
--------------------------------------------------------------------------------
/src/Logger.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Logger.cpp
3 | *
4 | * Created on: 31 mai 2017
5 | * Author: scerveau
6 | */
7 | #include "Logger.h"
8 |
9 | #include "CustomSettings.h"
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include
16 | #include
17 | #include
18 |
19 | G_LOCK_DEFINE_STATIC(logger);
20 |
21 | static long int getThreadID() {
22 | return quintptr(QThread::currentThreadId());
23 | }
24 |
25 | void
26 | Logger::configure_logger ()
27 | {
28 | QString lastGstDebugString = CustomSettings::lastGstDebugString ();
29 | qputenv(lastGstDebugString.split("=").at(0).toStdString ().c_str(),
30 | lastGstDebugString.split("=").at(1).toLocal8Bit());
31 | qputenv("GST_DEBUG_NO_COLOR", QByteArray("1"));
32 | qputenv("GST_DEBUG_FILE", QByteArray("gst_pipeviz.txt"));
33 | }
34 |
35 | Logger::Logger()
36 | : QThread(),
37 | m_fExit(false),
38 | m_level(MAX_LOG_LEVEL)
39 | {
40 | }
41 |
42 | Logger& Logger::instance()
43 | {
44 | static Logger instance;
45 | return instance;
46 | }
47 |
48 | void Logger::Quit()
49 | {
50 | m_fExit = true;
51 | wait();
52 | }
53 |
54 | void Logger::createLog(TimeStampFlag flag, const char* format, ...)
55 | {
56 | // first check if we should add the timestamp before the string
57 | char* new_fmt = NULL;
58 | if (flag == Logger::UseTimeStamp) {
59 | QString szTimestamp(QTime::currentTime().toString("HH:mm:ss:zzz"));
60 |
61 | const char* fmt_template = "%s %d 0x%x %s";
62 | int len = snprintf(NULL, 0, fmt_template, szTimestamp.toStdString().c_str(), getThreadID(), std::this_thread::get_id(), format);
63 | if (len < 0) {
64 | // cannot parse the string
65 | return;
66 | }
67 | len++; // add 1 byte for the additional terminating null character
68 | new_fmt = static_cast(malloc(sizeof(char) * len));
69 | snprintf(new_fmt, len, fmt_template, szTimestamp.toStdString().c_str(), getThreadID(), std::this_thread::get_id(), format);
70 | }
71 |
72 | // create the actual string (timestamp + format...)
73 | const char* formatString = new_fmt ? new_fmt : format;
74 | assert(formatString);
75 |
76 | va_list aptr;
77 | va_start(aptr, format);
78 | va_list argcopy; // copy the va_list and use vsnprintf to get the length of the final string
79 | va_copy(argcopy, aptr);
80 | int len = vsnprintf(NULL, 0, formatString , argcopy);
81 | va_end(argcopy);
82 | if (len < 0) {
83 | // cannot parse the string
84 | g_free(new_fmt);
85 | va_end(aptr);
86 | return;
87 | }
88 |
89 | len++; // add 1 byte for the additional terminating null character.
90 | char* buffer = static_cast(malloc(sizeof(char) * len));
91 | int actualLen = vsprintf(buffer, formatString, aptr);
92 | va_end(aptr);
93 | formatString = 0;
94 | g_free (new_fmt);
95 | if (actualLen < 0) {
96 | g_free (buffer);
97 | return;
98 | }
99 | // if lengths are different, our code is bugged
100 | assert((actualLen + 1) == len);
101 |
102 | // dump the final string
103 | G_LOCK(logger);
104 | processLog(buffer);
105 | G_UNLOCK(logger);
106 |
107 | // free the buffer and flush the logs
108 | g_free(buffer);
109 | }
110 |
111 | void Logger::incrementLogLevel() {
112 | m_level++;
113 | if (m_level > MAX_LOG_LEVEL)
114 | m_level = MAX_LOG_LEVEL;
115 | char buffer[32];
116 | sprintf(buffer,"logger log level %d\n",m_level);
117 | processLog(buffer);
118 | }
119 |
120 | void Logger::processLog(const QString& line)
121 | {
122 | emit sendLog(line,eLOG_CATEGORY_INTERNAL);
123 | }
124 |
125 | //#define GST_TIME_FORMAT "u:%02u:%02u.%09u"
126 | #define GST_TIME_FORMAT "%s"
127 | #define PRINT_FMT " " PID_FMT " " PTR_FMT " %s " CAT_FMT " %s\n"
128 |
129 | struct GSTLog {
130 | gchar* date;
131 | gchar* pid;
132 | gchar* level;
133 | gchar* category;
134 | gchar* file;
135 | gchar* line;
136 | gchar* function;
137 | gchar* obj;
138 | gchar* message;
139 | };
140 |
141 | void Logger::processGstLog(gchar* log)
142 | {
143 | // GSTLog gstLog;
144 | if(!g_strrstr(log,"WARN") && !g_strrstr(log,"ERROR"))
145 | return;
146 | /* GList* stringList = parseGstLine(log, ' ', 6);
147 | GList* l;
148 |
149 | gstLog.date = g_strdup((gchar*)g_list_nth_data(stringList, 0));
150 | gstLog.pid = g_strdup((gchar*)g_list_nth_data(stringList, 1));
151 | gstLog.level = g_strdup((gchar*)g_list_nth_data(stringList, 2));
152 | gstLog.category = g_strdup((gchar*)g_list_nth_data(stringList, 3));
153 |
154 | gstLog.file = g_strdup((gchar*)g_list_nth_data(stringList, 4));
155 | gstLog.line = g_strdup((gchar*)g_list_nth_data(stringList, 5));
156 | gstLog.function = g_strdup((gchar*)g_list_nth_data(stringList, 6));
157 | gstLog.obj = g_strdup((gchar*)g_list_nth_data(stringList, 7));
158 |
159 | QString message = "";
160 | for (l = stringList; l != NULL; l = l->next) {
161 | message += (gchar*)l->data;
162 | message += " ";
163 | }
164 | */
165 | emit sendLog(log,eLOG_CATEGORY_GST);
166 | }
167 |
168 | #define MAX_LINE_LENGTH 128
169 |
170 | GList* Logger::parseGstLine(gchar* line, gchar delimiter, int max_fields)
171 | {
172 | int count = 0;
173 | size_t pos = 0;
174 | char *lineBuffer = NULL;
175 |
176 | gboolean new_string=TRUE;
177 | GList* strList = NULL;
178 | gint n_fields = 0;
179 |
180 | int maximumLineLength = MAX_LINE_LENGTH;
181 |
182 | if (line == NULL)
183 | return NULL;
184 |
185 | do {
186 | if (new_string) {
187 | if (line[pos] != delimiter) {
188 | new_string = FALSE;
189 | lineBuffer = (gchar *)malloc(sizeof(char) * maximumLineLength);
190 | count=0;
191 | lineBuffer[count++] = line[pos];
192 | }
193 | }
194 | else {
195 | if (count == MAX_LINE_LENGTH) {
196 | maximumLineLength += MAX_LINE_LENGTH;
197 | lineBuffer = (gchar*)realloc(lineBuffer, maximumLineLength);
198 | }
199 | if (line[pos] == delimiter || line[pos] == '\0') {
200 | lineBuffer[count] = '\0';
201 | new_string= TRUE;
202 | strList = g_list_append(strList, g_strdup(lineBuffer));
203 | g_free(lineBuffer);
204 | n_fields++;
205 | if (max_fields != -1 && n_fields == max_fields) {
206 | pos++;
207 | if (pos < strlen(line))
208 | strList = g_list_append(strList, g_strdup(&line[pos]));
209 | break;
210 | }
211 | } else {
212 | lineBuffer[count++] = line[pos];
213 | }
214 |
215 | }
216 | pos++;
217 | } while (pos < strlen(line));
218 |
219 |
220 | return strList;
221 | }
222 |
223 | gchar *Logger::readGstLine(FILE *file)
224 | {
225 | int count = 0;
226 | char ch;
227 | char *line = NULL;
228 | gchar *lineBuffer = NULL;
229 | int maximumLineLength = MAX_LINE_LENGTH;
230 |
231 | if (file == NULL)
232 | goto beach;
233 |
234 | lineBuffer = (gchar *)malloc(sizeof(char) * maximumLineLength);
235 | if (lineBuffer == NULL)
236 | goto beach;
237 |
238 |
239 | ch = getc(file);
240 | while ((ch != '\n') && (ch != EOF)) {
241 | if (count == maximumLineLength) {
242 | maximumLineLength += MAX_LINE_LENGTH;
243 | lineBuffer = (gchar*)realloc(lineBuffer, maximumLineLength);
244 | if (lineBuffer == NULL)
245 | goto beach;
246 | }
247 | lineBuffer[count] = ch;
248 | count++;
249 |
250 | ch = getc(file);
251 | }
252 | if(count==0)
253 | goto beach;
254 |
255 | lineBuffer[count] = '\0';
256 | lineBuffer = (gchar*)realloc(lineBuffer, count + 1);
257 | line = g_strdup(lineBuffer);
258 | //qDebug() << lineBuffer;
259 | //qDebug() << line;
260 | beach:
261 | g_free(lineBuffer);
262 | return line;
263 | }
264 |
265 | void Logger::run()
266 | {
267 | FILE* file;
268 | gchar* line;
269 |
270 | file = fopen("gst_pipeviz.txt", "r");
271 | if(!file)
272 | return;
273 |
274 | while (!m_fExit) {
275 | line = readGstLine(file);
276 | if (line != NULL) {
277 | processGstLog(line);
278 | g_free(line);
279 | } else
280 | usleep(10000);
281 | }
282 |
283 | qDebug() << "Logger closed";
284 |
285 | fclose(file);
286 |
287 | }
288 |
--------------------------------------------------------------------------------
/src/Logger.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Logger.h
3 | *
4 | * Created on: 31 mai 2017
5 | * Author: scerveau
6 | */
7 |
8 | #ifndef LOGGER_H_
9 | #define LOGGER_H_
10 |
11 | #include
12 | #include "glib.h"
13 |
14 | enum eLogCategory {
15 | eLOG_CATEGORY_INTERNAL,
16 | eLOG_CATEGORY_GST,
17 | eLOG_CATEGORY_EVENTS,
18 | };
19 |
20 | #ifndef LOG_LEVEL
21 | # define LOG_LEVEL 1
22 | #endif
23 |
24 | #define MAX_LOG_LEVEL 3
25 |
26 | #ifndef CLASS_LOGGER_TAG
27 | # define CLASS_LOGGER_TAG __BASE_FILE__
28 | #endif
29 |
30 |
31 | class Logger : public QThread {
32 | Q_OBJECT
33 | public:
34 | enum TimeStampFlag {
35 | UseTimeStamp = 0,
36 | NoTimeStamp,
37 | };
38 |
39 | Logger();
40 | void configure_logger();
41 |
42 | static Logger& instance();
43 | void Quit();
44 |
45 | void processLog(const QString& line);
46 | void createLog(Logger::TimeStampFlag, const char* format, ...);
47 | int getLevel() const { return m_level; }
48 | void incrementLogLevel();
49 |
50 | protected:
51 | void processGstLog(gchar* line);
52 | gchar* readGstLine(FILE *file);
53 | GList* parseGstLine(gchar* line, gchar ch = ' ', int max_field = -1);
54 |
55 | signals:
56 | void sendLog(const QString& message, int category);
57 |
58 | private:
59 | void run();
60 | bool m_fExit;
61 | int m_level;
62 | };
63 |
64 | #define log_debug(LEVEL,TYPE,FMT, ARGS...) do { \
65 | if (LEVEL <= Logger::instance().getLevel()) \
66 | Logger::instance().createLog(Logger::UseTimeStamp, "" TYPE ": " FMT "", ## ARGS); \
67 | } while (0)
68 | #define log_debug_no_time_stderr(LEVEL,TYPE,FMT, ARGS...) do { \
69 | Logger::instance().createLog(Logger::NoTimeStamp, "" FMT "", ## ARGS); \
70 | } while (0)
71 |
72 | #define LOG_IMPORTANT(FMT, ARGS...) log_debug_no_time_stderr(0, "",FMT ,## ARGS)
73 |
74 | #ifndef DISABLE_LOG
75 | # define LOG_ERROR(FMT, ARGS...) log_debug(0, "ERROR\t" CLASS_LOGGER_TAG ":%d:%s", FMT,__LINE__, __func__, ## ARGS)
76 | # define LOG_WARNING(FMT, ARGS...) log_debug(1, "WARN\t" CLASS_LOGGER_TAG ":%d:%s", FMT, __LINE__, __func__, ## ARGS)
77 | # define LOG_INFO(FMT, ARGS...) log_debug(2, "INFO\t" CLASS_LOGGER_TAG ":%d:%s", FMT, __LINE__, __func__, ## ARGS)
78 | # define LOG_DEBUG(FMT, ARGS...) log_debug(3, "DEBUG\t" CLASS_LOGGER_TAG ":%d:%s", FMT, __LINE__, __func__, ## ARGS)
79 | #else
80 | # define LOG_ERROR(FMT, ARGS...)
81 | # define LOG_WARNING(FMT, ARGS...)
82 | # define LOG_INFO(FMT, ARGS...)
83 | # define LOG_DEBUG(FMT, ARGS...)
84 | #endif
85 |
86 | #endif /* LOGGER_H_ */
87 |
--------------------------------------------------------------------------------
/src/MainWindow.cpp:
--------------------------------------------------------------------------------
1 | #include "MainWindow.h"
2 |
3 | #include "PluginsList.h"
4 | #include "FavoritesList.h"
5 |
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 |
26 | #include "CustomSettings.h"
27 | #include "GraphDisplay.h"
28 | #include "PipelineIE.h"
29 | #include "SeekSlider.h"
30 |
31 | #include "version_info.h"
32 |
33 | #include
34 |
35 | MainWindow::MainWindow (QWidget *parent, Qt::WindowFlags flags)
36 | : QMainWindow (parent, flags),
37 | m_pGraph (new GraphManager)
38 | {
39 | QToolBar *ptb = addToolBar ("Menu");
40 |
41 | QAction *pactAdd = ptb->addAction ("Add...");
42 | pactAdd->setShortcut (QKeySequence ("Ctrl+F"));
43 | connect (pactAdd, SIGNAL (triggered ()), SLOT (AddPlugin ()));
44 |
45 | QAction *pactOpenFile = ptb->addAction ("Open Media File...");
46 | connect (pactOpenFile, SIGNAL (triggered ()), SLOT (OpenMediaFile ()));
47 |
48 | ptb->addSeparator ();
49 |
50 | QPixmap pxPlay (24, 24);
51 | pxPlay.fill (QColor (0, 0, 0, 0));
52 | QPainter pntrPlay (&pxPlay);
53 | pntrPlay.setPen (Qt::darkGreen);
54 | pntrPlay.setBrush (QBrush (Qt::darkGreen));
55 |
56 | QPolygon polygon (3);
57 | polygon.setPoint (0, 4, 4);
58 | polygon.setPoint (1, 4, 20);
59 | polygon.setPoint (2, 20, 12);
60 |
61 | pntrPlay.drawPolygon (polygon, Qt::WindingFill);
62 |
63 | QAction *pactPlay = ptb->addAction (QIcon (pxPlay), "Play");
64 | connect (pactPlay, SIGNAL (triggered ()), SLOT (Play ()));
65 |
66 | QPixmap pxPause (24, 24);
67 | pxPause.fill (QColor (0, 0, 0, 0));
68 | QPainter pntrPause (&pxPause);
69 | pntrPause.setPen (Qt::darkGray);
70 | pntrPause.setBrush (QBrush (Qt::darkGray));
71 |
72 | pntrPause.drawRect (8, 4, 3, 16);
73 | pntrPause.drawRect (13, 4, 3, 16);
74 |
75 | QAction *pactPause = ptb->addAction (QIcon (pxPause), "Pause");
76 | connect (pactPause, SIGNAL (triggered ()), SLOT (Pause ()));
77 |
78 | QPixmap pxStop (24, 24);
79 | pxStop.fill (QColor (0, 0, 0, 0));
80 | QPainter pntrStop (&pxStop);
81 | pntrStop.setPen (Qt::darkRed);
82 | pntrStop.setBrush (QBrush (Qt::darkRed));
83 |
84 | pntrStop.drawRect (6, 6, 12, 12);
85 |
86 | QAction *pactStop = ptb->addAction (QIcon (pxStop), "Stop");
87 | connect (pactStop, SIGNAL (triggered ()), SLOT (Stop ()));
88 |
89 | QPixmap pxFulsh (24, 24);
90 | pxFulsh.fill (QColor (0, 0, 0, 0));
91 | QPainter pntrFlush (&pxFulsh);
92 | pntrFlush.setPen (Qt::darkGreen);
93 | pntrFlush.setBrush (QBrush (Qt::darkGreen));
94 |
95 | pntrFlush.drawRect (3, 4, 3, 16);
96 |
97 | polygon = QPolygon (3);
98 | polygon.setPoint (0, 9, 4);
99 | polygon.setPoint (1, 9, 20);
100 | polygon.setPoint (2, 21, 12);
101 |
102 | pntrFlush.drawPolygon (polygon, Qt::WindingFill);
103 |
104 | QAction *pactFlush = ptb->addAction (QIcon (pxFulsh), "Flush");
105 | connect (pactFlush, SIGNAL (triggered ()), SLOT (Flush ()));
106 |
107 | QAction *pactClear = ptb->addAction ("Clear");
108 | connect (pactClear, SIGNAL (triggered ()), SLOT (ClearGraph ()));
109 | ptb->addSeparator ();
110 |
111 | m_pslider = new SeekSlider ();
112 | m_pslider->setOrientation (Qt::Horizontal);
113 | m_pslider->setRange (0, 10000);
114 | m_pslider->setTracking (false);
115 |
116 | connect(m_pslider, SIGNAL(valueChanged(int)), SLOT(Seek(int)));
117 | ptb->addWidget (m_pslider);
118 |
119 | m_menu = menuBar ()->addMenu ("&File");
120 |
121 | QAction *pactOpen = m_menu->addAction ("Open...", this, SLOT (Open ()),
122 | QKeySequence::Open);
123 | addAction (pactOpen);
124 |
125 | QAction *pactOpenMediaFile = m_menu->addAction ("Open Media File...", this,
126 | SLOT (OpenMediaFile ()),
127 | QKeySequence::Open);
128 | addAction (pactOpenMediaFile);
129 |
130 | QAction *pactSave = m_menu->addAction ("Save", this, SLOT (Save ()),
131 | QKeySequence::Save);
132 | addAction (pactSave);
133 |
134 | QAction *pactSaveAs = m_menu->addAction ("Save As...", this, SLOT (SaveAs ()),
135 | QKeySequence::SaveAs);
136 | addAction (pactSaveAs);
137 |
138 | m_menu->addSeparator ();
139 | m_menu->addAction ("Exit", this, SLOT (close ()));
140 |
141 | m_menu = menuBar ()->addMenu ("&Graph");
142 |
143 | m_menu->addAction (pactAdd);
144 | m_menu->addAction (pactOpenMediaFile);
145 | m_menu->addAction ("Open Media Uri...", this, SLOT (OpenMediaUri ()));
146 | m_menu->addSeparator ();
147 | m_menu->addAction (pactPlay);
148 | m_menu->addAction (pactPause);
149 | m_menu->addAction (pactStop);
150 | m_menu->addAction (pactFlush);
151 | m_menu->addSeparator ();
152 | m_menu->addAction (pactClear);
153 |
154 | m_menu = menuBar ()->addMenu ("&Help");
155 |
156 | m_menu->addAction ("About pipeviz...", this, SLOT (About ()));
157 |
158 | m_pGraphDisplay = new GraphDisplay(this);
159 | connect(m_pGraphDisplay, SIGNAL(signalAddPlugin()),
160 | this, SLOT(AddPlugin()));
161 | connect(m_pGraphDisplay, SIGNAL(signalClearGraph()),
162 | this, SLOT(ClearGraph()));
163 |
164 | QScrollArea *pscroll = new QScrollArea;
165 | pscroll->setWidget (m_pGraphDisplay);
166 | pscroll->setWidgetResizable (false);
167 | m_pGraphDisplay->resize (10000, 10000);
168 | m_pGraphDisplay->m_pGraph = m_pGraph;
169 | setCentralWidget (pscroll);
170 | m_pstatusBar = new QStatusBar;
171 | setStatusBar (m_pstatusBar);
172 | m_pluginListDlg = new PluginsListDialog (this);
173 | m_pluginListDlg->setModal (false);
174 |
175 | connect(m_pluginListDlg, SIGNAL(signalAddPluginToFav(const QString&)),
176 | this, SLOT(AddPluginToFavorites(const QString&)));
177 | connect(m_pluginListDlg, SIGNAL(signalRemPluginToFav(const QString&)),
178 | this, SLOT(RemovePluginToFavorites(const QString&)));
179 |
180 |
181 | restoreGeometry (CustomSettings::mainWindowGeometry ());
182 | createDockWindows();
183 |
184 | Logger::instance().start();
185 | connect(&Logger::instance(), SIGNAL(sendLog(const QString &, int)),
186 | this, SLOT(InsertLogLine(const QString &, int)));
187 |
188 | LOG_INFO("Mainwindow is now initialized");
189 |
190 | startTimer (100);
191 | }
192 |
193 | void MainWindow::createDockWindows()
194 | {
195 | /* create the log list window */
196 | QDockWidget *dock = new QDockWidget(tr("logs"), this);
197 | dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
198 | m_logList = new QListWidget(dock);
199 | dock->setWidget(m_logList);
200 | addDockWidget(Qt::BottomDockWidgetArea, dock);
201 | m_menu->addAction(dock->toggleViewAction());
202 |
203 | /*create the favorite list window */
204 | dock = new QDockWidget(tr("favorite list"), this);
205 | dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
206 | m_favoriteList = new FavoritesList(dock);
207 | dock->setWidget(m_favoriteList);
208 | addDockWidget(Qt::RightDockWidgetArea, dock);
209 | m_menu->addAction(dock->toggleViewAction());
210 | connect(m_favoriteList, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
211 | this, SLOT(onFavoriteListItemDoubleClicked(QListWidgetItem*)));
212 | m_favoriteList->setContextMenuPolicy(Qt::CustomContextMenu);
213 | connect(m_favoriteList,SIGNAL(customContextMenuRequested(const QPoint &)),
214 | this,SLOT(ProvideContextMenu(const QPoint &)));
215 |
216 | }
217 | FavoritesList* MainWindow::getFavoritesList()
218 | {
219 | return m_favoriteList;
220 | }
221 |
222 | void MainWindow::AddPluginToFavorites(const QString& plugin_name)
223 | {
224 | m_favoriteList->addFavorite(plugin_name);
225 | }
226 |
227 | void MainWindow::RemovePluginToFavorites(const QString& plugin_name)
228 | {
229 | m_favoriteList->removeFavorite(plugin_name);
230 | }
231 |
232 | void MainWindow::onFavoriteListItemDoubleClicked(QListWidgetItem* pitem)
233 | {
234 | LOG_INFO("onFavoriteListItemDoubleClicked: %s", pitem->text().toStdString ().c_str ());
235 | if (!m_pGraph
236 | || !m_pGraph->AddPlugin (pitem->text ().toStdString ().c_str (), NULL)) {
237 | QMessageBox::warning (
238 | this, "Plugin addition problem",
239 | "Plugin `" + pitem->text () + "` insertion was FAILED");
240 | LOG_INFO("Plugin '%s' insertion FAILED", pitem->text ().toStdString ().c_str ());
241 | return;
242 | }
243 | }
244 |
245 | void MainWindow::ProvideContextMenu(const QPoint &pos)
246 | {
247 | QPoint item = m_favoriteList->mapToGlobal(pos);
248 | QMenu submenu;
249 | submenu.addAction("Delete");
250 | QAction* rightClickItem = submenu.exec(item);
251 | if (rightClickItem && rightClickItem->text().contains("Delete") ) {
252 | LOG_INFO("Delete item: %s", m_favoriteList->currentItem()->text().toStdString ().c_str ());
253 | RemovePluginToFavorites(m_favoriteList->currentItem()->text());
254 | }
255 | }
256 |
257 | void MainWindow::InsertLogLine(const QString& line, int category)
258 | {
259 | QListWidgetItem* pItem =new QListWidgetItem(line);
260 | switch(category) {
261 | case eLOG_CATEGORY_INTERNAL:
262 | pItem->setForeground(Qt::blue);
263 | break;
264 | case eLOG_CATEGORY_GST:
265 | pItem->setForeground(Qt::red);
266 | break;
267 | default:
268 | pItem->setForeground(Qt::black);
269 | }
270 | m_logList->addItem(pItem);
271 | }
272 |
273 | MainWindow& MainWindow::instance()
274 | {
275 | static MainWindow instance;
276 | return instance;
277 | }
278 |
279 | MainWindow::~MainWindow ()
280 | {
281 | CustomSettings::saveMainWindowGeometry (saveGeometry ());
282 | Logger::instance().Quit();
283 | delete m_pluginListDlg;
284 | }
285 |
286 | void
287 | MainWindow::AddPlugin ()
288 | {
289 | m_pluginListDlg->setGraph (m_pGraph.data ());
290 |
291 | m_pluginListDlg->raise ();
292 | m_pluginListDlg->show ();
293 | std::vector info = m_pGraph->GetInfo ();
294 | m_pGraphDisplay->update (info);
295 | }
296 |
297 | void
298 | MainWindow::OpenMediaFile ()
299 | {
300 | QString dir = CustomSettings::lastIODirectory ();
301 |
302 | QString path = QFileDialog::getOpenFileName (this, "Open File...", dir);
303 | if (!path.isEmpty ()) {
304 | gchar *uri = gst_filename_to_uri (path.toStdString ().c_str (), NULL);
305 | if (uri) {
306 | LOG_INFO("Open Source file: %s", path.toStdString ().c_str ());
307 |
308 | m_pGraph->OpenUri (uri, NULL);
309 | g_free (uri);
310 |
311 | std::vector info = m_pGraph->GetInfo ();
312 | m_pGraphDisplay->update (info);
313 |
314 | QString dir = QFileInfo (path).absoluteDir ().absolutePath ();
315 | CustomSettings::saveLastIODirectory (dir);
316 | }
317 | }
318 | }
319 |
320 | void
321 | MainWindow::OpenMediaUri ()
322 | {
323 | QString uri = QInputDialog::getText (this, "Open Uri...", "Uri:");
324 |
325 | if (!uri.isEmpty ()) {
326 | LOG_INFO("Open uri: %s", uri.toStdString ().c_str ());
327 | m_pGraph->OpenUri (uri.toStdString ().c_str (), NULL);
328 |
329 | std::vector info = m_pGraph->GetInfo ();
330 | m_pGraphDisplay->update (info);
331 | }
332 | }
333 |
334 | void
335 | MainWindow::Play ()
336 | {
337 | LOG_INFO( "Play");
338 | m_pGraph->Play ();
339 | }
340 |
341 | void
342 | MainWindow::Pause ()
343 | {
344 | LOG_INFO("Pause");
345 | m_pGraph->Pause ();
346 | }
347 |
348 | void
349 | MainWindow::Stop ()
350 | {
351 | LOG_INFO("Stop");
352 | m_pGraph->Stop ();
353 | }
354 |
355 | void
356 | MainWindow::Flush ()
357 | {
358 | LOG_INFO("Flush");
359 |
360 | if (m_pGraph->m_pGraph) {
361 | gst_element_send_event (GST_ELEMENT (m_pGraph->m_pGraph),
362 | gst_event_new_flush_start ());
363 | #if GST_VERSION_MAJOR >= 1
364 | gst_element_send_event(GST_ELEMENT(m_pGraph -> m_pGraph), gst_event_new_flush_stop(true));
365 | #else
366 | gst_element_send_event (GST_ELEMENT (m_pGraph->m_pGraph),
367 | gst_event_new_flush_stop ());
368 | #endif
369 | }
370 | }
371 |
372 | void
373 | MainWindow::ClearGraph ()
374 | {
375 | LOG_INFO("ClearGraph");
376 | PipelineIE::Clear (m_pGraph);
377 | }
378 |
379 | void
380 | MainWindow::Seek (int val)
381 | {
382 | if (m_pGraph->SetPosition ((double) (val) / m_pslider->maximum ()))
383 | LOG_INFO("Seek to %d", val);
384 | else
385 | LOG_INFO("Seek FAILED");
386 | }
387 |
388 | void
389 | MainWindow::timerEvent (QTimerEvent *)
390 | {
391 | GstState state;
392 | GstStateChangeReturn res = gst_element_get_state (m_pGraph->m_pGraph, &state,
393 | NULL,
394 | GST_MSECOND);
395 |
396 | if (res == GST_STATE_CHANGE_SUCCESS) {
397 | QString str;
398 | switch (state) {
399 | case GST_STATE_VOID_PENDING:
400 | str = "Pending";
401 | break;
402 | case GST_STATE_NULL:
403 | str = "Null";
404 | break;
405 | case GST_STATE_READY:
406 | str = "Ready";
407 | break;
408 | case GST_STATE_PAUSED:
409 | str = "Paused";
410 | break;
411 | case GST_STATE_PLAYING:
412 | str = "Playing";
413 | break;
414 | };
415 |
416 | m_pstatusBar->showMessage (str);
417 | }
418 | else {
419 | m_pstatusBar->showMessage (
420 | QString (gst_element_state_change_return_get_name (res)));
421 | }
422 |
423 | double pos = m_pGraph->GetPosition ();
424 |
425 | if (m_pslider->value () != (int) (m_pslider->maximum () * pos))
426 | m_pslider->setSliderPosition (m_pslider->maximum () * pos);
427 |
428 | m_pGraphDisplay->update (m_pGraph->GetInfo ());
429 | }
430 |
431 | void
432 | MainWindow::Save ()
433 | {
434 | if (m_fileName.isEmpty ())
435 | SaveAs ();
436 | else {
437 | QFileInfo fileInfo (m_fileName);
438 | if (fileInfo.completeSuffix ().isEmpty ()
439 | || fileInfo.completeSuffix () != "gpi")
440 | m_fileName = m_fileName + ".gpi";
441 |
442 | PipelineIE::Export (m_pGraph, m_fileName);
443 |
444 | }
445 | }
446 |
447 | void
448 | MainWindow::SaveAs ()
449 | {
450 | QString dir = CustomSettings::lastIODirectory ();
451 |
452 | QString path = QFileDialog::getSaveFileName (this, "Save As...", dir,
453 | tr ("*.gpi"));
454 |
455 | if (!path.isEmpty ()) {
456 | m_fileName = path;
457 | Save ();
458 |
459 | QString dir = QFileInfo (path).absoluteDir ().absolutePath ();
460 | CustomSettings::saveLastIODirectory (dir);
461 | }
462 | }
463 |
464 | void
465 | MainWindow::Open ()
466 | {
467 | QString dir = CustomSettings::lastIODirectory ();
468 |
469 | QString path = QFileDialog::getOpenFileName (
470 | this, "Open...", dir, tr ("GPI (*.gpi *.xpm);;All files (*.*)"));
471 |
472 | if (!path.isEmpty ()) {
473 | if (PipelineIE::Import (m_pGraph, path))
474 | m_fileName = path;
475 |
476 | QString dir = QFileInfo (path).absoluteDir ().absolutePath ();
477 | CustomSettings::saveLastIODirectory (dir);
478 | }
479 | }
480 |
481 | void
482 | MainWindow::About ()
483 | {
484 | QString message;
485 | message = "pipeviz
";
486 | message = "virinext@gmail.com
";
487 | message += QString ("Version: ") + VERSION_STR + "
";
488 | message += "GUI Based on Qt";
489 | message += "using ";
490 | message += gst_version_string ();
491 | message += "";
492 |
493 | QMessageBox::about (this, "About", message);
494 | }
495 |
--------------------------------------------------------------------------------
/src/MainWindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAIN_WINDOW_H_
2 | #define MAIN_WINDOW_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include "GraphManager.h"
17 | #include "Logger.h"
18 |
19 | class GraphDisplay;
20 | class PluginsListDialog;
21 | class FavoritesList;
22 |
23 | class MainWindow: public QMainWindow
24 | {
25 | Q_OBJECT
26 | public:
27 | MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
28 | ~MainWindow();
29 |
30 | static MainWindow& instance();
31 | FavoritesList* getFavoritesList();
32 |
33 | protected:
34 | void timerEvent(QTimerEvent *);
35 | void createDockWindows();
36 |
37 | public slots:
38 | void InsertLogLine(const QString& line, int category);
39 | void AddPlugin();
40 | void ClearGraph();
41 | void AddPluginToFavorites(const QString& plugin_name);
42 | void RemovePluginToFavorites(const QString& plugin_name);
43 |
44 | private slots:
45 | void OpenMediaFile();
46 | void OpenMediaUri();
47 | void Play();
48 | void Pause();
49 | void Stop();
50 | void Flush();
51 | void Seek(int);
52 |
53 | void Save();
54 | void SaveAs();
55 | void Open();
56 |
57 | void About();
58 |
59 |
60 | void onFavoriteListItemDoubleClicked(QListWidgetItem* item);
61 | void ProvideContextMenu(const QPoint &pos);
62 |
63 | private:
64 | QSharedPointer m_pGraph;
65 |
66 | GraphDisplay *m_pGraphDisplay;
67 |
68 | QStatusBar *m_pstatusBar;
69 | QSlider *m_pslider;
70 |
71 | QString m_fileName;
72 | PluginsListDialog *m_pluginListDlg;
73 | QMenu *m_menu;
74 | QListWidget* m_logList;
75 | FavoritesList* m_favoriteList;
76 | };
77 |
78 | #endif
79 |
--------------------------------------------------------------------------------
/src/PadProperties.cpp:
--------------------------------------------------------------------------------
1 | #include "PadProperties.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | PadProperties::PadProperties (QSharedPointer pGraphManager,
11 | const char *elementName, const char *padName,
12 | QWidget *parent, Qt::WindowFlags flags)
13 | : QWidget (parent, flags)
14 | {
15 | setWindowTitle (QString (elementName) + "::" + padName + " properties");
16 | GstElement *element = gst_bin_get_by_name (GST_BIN (pGraphManager->m_pGraph),
17 | elementName);
18 |
19 | if (!element)
20 | return;
21 |
22 | GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (element), padName);
23 |
24 | QGridLayout *play = new QGridLayout;
25 |
26 | play->addWidget (new QLabel ("Name"), 0, 0);
27 |
28 | QLabel *plbl = new QLabel (padName);
29 | plbl->setTextInteractionFlags (
30 | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
31 | play->addWidget (plbl, 0, 1);
32 |
33 | play->addWidget (new QLabel ("All caps:"), 1, 0);
34 | #if GST_VERSION_MAJOR >= 1
35 | GstCaps *caps = gst_pad_query_caps(pad, NULL);
36 | #else
37 | GstCaps *caps = gst_pad_get_caps (pad);
38 | #endif
39 | gchar *str;
40 | gchar *noSpecified = (gchar *) "not specified";
41 | if (caps)
42 | str = gst_caps_to_string (caps);
43 | else
44 | str = noSpecified;
45 |
46 | plbl = new QLabel (QString (str));
47 | plbl->setTextInteractionFlags (
48 | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
49 | play->addWidget (plbl, 1, 1);
50 | if (caps) {
51 | g_free (str);
52 | gst_caps_unref (caps);
53 | }
54 |
55 | play->addWidget (new QLabel ("Allowed caps:"), 2, 0);
56 | caps = gst_pad_get_allowed_caps (pad);
57 | str = NULL;
58 | if (caps)
59 | str = gst_caps_to_string (caps);
60 | else
61 | str = noSpecified;
62 |
63 | plbl = new QLabel (QString (str));
64 | plbl->setTextInteractionFlags (
65 | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
66 | play->addWidget (plbl, 2, 1);
67 | if (caps) {
68 | g_free (str);
69 | gst_caps_unref (caps);
70 | }
71 |
72 | play->addWidget (new QLabel ("Current caps"), 3, 0);
73 | #if GST_VERSION_MAJOR >= 1
74 | caps = gst_pad_get_current_caps(pad);
75 | #else
76 | caps = gst_pad_get_negotiated_caps (pad);
77 | #endif
78 | str = NULL;
79 | if (caps)
80 | str = gst_caps_to_string (caps);
81 | else
82 | str = noSpecified;
83 |
84 | plbl = new QLabel (QString (str));
85 | plbl->setTextInteractionFlags (
86 | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
87 | play->addWidget (plbl, 3, 1);
88 | if (caps) {
89 | g_free (str);
90 | gst_caps_unref (caps);
91 | }
92 |
93 | gst_object_unref (element);
94 | gst_object_unref (pad);
95 |
96 | QVBoxLayout *pvblay = new QVBoxLayout;
97 | QWidget *pwgt = new QWidget (this);
98 | pwgt->setLayout (play);
99 | QScrollArea *pscroll = new QScrollArea (this);
100 | pscroll->setWidget (pwgt);
101 |
102 | pvblay->addWidget (pscroll);
103 |
104 | setLayout (pvblay);
105 | }
106 |
--------------------------------------------------------------------------------
/src/PadProperties.h:
--------------------------------------------------------------------------------
1 | #ifndef PAD_PROPERTIES_H_
2 | #define PAD_PROPERTIES_H_
3 |
4 | #include
5 | #include
6 |
7 | #include "GraphManager.h"
8 |
9 | class PadProperties: public QWidget
10 | {
11 | public:
12 | PadProperties(QSharedPointer pGraphManager, const char *element, const char *pad
13 | , QWidget *parent = 0, Qt::WindowFlags flags = 0);
14 | };
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/PipelineIE.cpp:
--------------------------------------------------------------------------------
1 | #include "PipelineIE.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 |
11 | static void
12 | clearPipeline (GstElement *pipeline)
13 | {
14 | if (!pipeline)
15 | return;
16 |
17 | GstIterator *iter;
18 | iter = gst_bin_iterate_elements (GST_BIN (pipeline));
19 | GstElement *element = NULL;
20 | bool done = false;
21 | while (!done) {
22 | #if GST_VERSION_MAJOR >= 1
23 | GValue value = G_VALUE_INIT;
24 | switch (gst_iterator_next (iter, &value))
25 | {
26 | case GST_ITERATOR_OK:
27 | {
28 | element = GST_ELEMENT(g_value_get_object(&value));
29 | #else
30 | switch (gst_iterator_next (iter, (gpointer *) &element)) {
31 | case GST_ITERATOR_OK: {
32 | #endif
33 | gst_bin_remove (GST_BIN (pipeline), element);
34 | #if GST_VERSION_MAJOR >= 1
35 | g_value_reset (&value);
36 | #endif
37 | iter = gst_bin_iterate_elements (GST_BIN (pipeline));
38 | if (!iter)
39 | done = true;
40 |
41 | break;
42 | }
43 | case GST_ITERATOR_DONE:
44 | case GST_ITERATOR_RESYNC:
45 | case GST_ITERATOR_ERROR: {
46 | done = true;
47 | break;
48 | }
49 | };
50 | }
51 |
52 | gst_iterator_free (iter);
53 | }
54 |
55 | namespace
56 | {
57 | struct Connection
58 | {
59 | std::string element1;
60 | std::string pad1;
61 | std::string element2;
62 | std::string pad2;
63 | };
64 | }
65 |
66 | static void
67 | writeProperties (QXmlStreamWriter &xmlWriter, const GstElement *element)
68 | {
69 | GParamSpec **prop_specs;
70 | guint num_props;
71 |
72 | prop_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (element),
73 | &num_props);
74 |
75 | if (!num_props)
76 | return;
77 |
78 | xmlWriter.writeStartElement ("properties");
79 |
80 | for (std::size_t i = 0; i < num_props; i++) {
81 | GParamSpec *param = prop_specs[i];
82 |
83 | if ((param->flags & G_PARAM_READABLE)
84 | && (param->flags & G_PARAM_WRITABLE)) {
85 | GValue value = G_VALUE_INIT;
86 | g_value_init (&value, param->value_type);
87 |
88 | g_object_get_property (G_OBJECT (element), param->name, &value);
89 |
90 | if (!g_param_value_defaults (param, &value)) {
91 | bool skip = false;
92 | QString propertyName = g_param_spec_get_name (param);
93 | QString propertyValue;
94 |
95 | switch (G_VALUE_TYPE (&value)) {
96 | case G_TYPE_STRING: {
97 |
98 | const char *string_val = g_value_get_string (&value);
99 | if (string_val)
100 | propertyValue = string_val;
101 | else
102 | skip = true;
103 | break;
104 | }
105 | case G_TYPE_BOOLEAN: {
106 | gboolean bool_val = g_value_get_boolean (&value);
107 | propertyValue = QString::number (bool_val);
108 | break;
109 | }
110 | case G_TYPE_ULONG: {
111 | propertyValue = QString::number (g_value_get_ulong (&value));
112 | break;
113 | }
114 | case G_TYPE_LONG: {
115 | propertyValue = QString::number (g_value_get_long (&value));
116 | break;
117 | }
118 | case G_TYPE_UINT: {
119 | propertyValue = QString::number (g_value_get_uint (&value));
120 | break;
121 | }
122 | case G_TYPE_INT: {
123 | propertyValue = QString::number (g_value_get_int (&value));
124 | break;
125 | }
126 | case G_TYPE_UINT64: {
127 | propertyValue = QString::number (g_value_get_uint64 (&value));
128 | break;
129 | }
130 | case G_TYPE_INT64: {
131 | propertyValue = QString::number (g_value_get_int64 (&value));
132 | break;
133 | }
134 | case G_TYPE_FLOAT: {
135 | propertyValue = QString::number (g_value_get_float (&value));
136 | break;
137 | }
138 | case G_TYPE_DOUBLE: {
139 | propertyValue = QString::number (g_value_get_double (&value));
140 | break;
141 | }
142 | default: {
143 | gchar *elementName = gst_element_get_name (element);
144 | LOG_INFO("property `%s` for `%s` not supported", propertyName.toStdString ().c_str (), elementName);
145 | g_free (elementName);
146 |
147 | skip = true;
148 | break;
149 | }
150 | };
151 |
152 | if (!skip) {
153 | xmlWriter.writeStartElement ("property");
154 | xmlWriter.writeAttribute ("name", propertyName);
155 | xmlWriter.writeAttribute ("value", propertyValue);
156 | xmlWriter.writeEndElement ();
157 | }
158 | g_value_reset (&value);
159 |
160 | }
161 | }
162 | }
163 |
164 | xmlWriter.writeEndElement ();
165 |
166 | g_free (prop_specs);
167 | }
168 |
169 | static void
170 | loadProperties (QDomElement node, GstElement *element)
171 | {
172 | QDomNode child = node.firstChild ();
173 | while (!child.isNull ()) {
174 | if (child.toElement ().tagName () == "property") {
175 | QString name = child.toElement ().attribute ("name");
176 | QString value = child.toElement ().attribute ("value");
177 |
178 | GParamSpec *param = g_object_class_find_property (
179 | G_OBJECT_GET_CLASS (element), name.toStdString ().c_str ());
180 |
181 | if (!param) {
182 | gchar *elementName = gst_element_get_name (element);
183 | LOG_INFO("problem with setting property `%s` for `%s`", name.toStdString ().c_str (), elementName);
184 | g_free (elementName);
185 | continue;
186 | }
187 |
188 | if (!(param->flags & G_PARAM_WRITABLE))
189 | continue;
190 |
191 | std::string tmpStr = name.toStdString ();
192 | const char *propName = tmpStr.c_str ();
193 | switch (param->value_type) {
194 | case G_TYPE_STRING: {
195 | g_object_set (G_OBJECT (element), propName,
196 | value.toStdString ().c_str (), NULL);
197 | break;
198 | }
199 | case G_TYPE_BOOLEAN: {
200 | gboolean val = value.toInt ();
201 | g_object_set (G_OBJECT (element), propName, val, NULL);
202 | break;
203 | }
204 | case G_TYPE_ULONG: {
205 | gulong val = value.toULong ();
206 | g_object_set (G_OBJECT (element), propName, val, NULL);
207 | break;
208 | }
209 | case G_TYPE_LONG: {
210 | glong val = value.toLong ();
211 | g_object_set (G_OBJECT (element), propName, val, NULL);
212 | break;
213 | }
214 | case G_TYPE_UINT: {
215 | guint val = value.toUInt ();
216 | g_object_set (G_OBJECT (element), propName, val, NULL);
217 | break;
218 | }
219 | case G_TYPE_INT: {
220 | gint val = value.toInt ();
221 | g_object_set (G_OBJECT (element), propName, val, NULL);
222 | break;
223 | }
224 | case G_TYPE_UINT64: {
225 | guint64 val = value.toULongLong ();
226 | g_object_set (G_OBJECT (element), propName, val, NULL);
227 | break;
228 | }
229 | case G_TYPE_INT64: {
230 | gint64 val = value.toLongLong ();
231 | g_object_set (G_OBJECT (element), propName, val, NULL);
232 | break;
233 | }
234 | case G_TYPE_FLOAT: {
235 | gfloat val = value.toFloat ();
236 | g_object_set (G_OBJECT (element), propName, val, NULL);
237 | break;
238 | }
239 | case G_TYPE_DOUBLE: {
240 | gdouble val = value.toDouble ();
241 | g_object_set (G_OBJECT (element), propName, val, NULL);
242 | break;
243 | }
244 | default: {
245 | gchar *elementName = gst_element_get_name (element);
246 | LOG_INFO("property `%s` for `%s` not supported", propName, elementName);
247 | g_free (elementName);
248 | break;
249 | }
250 | };
251 | }
252 |
253 | child = child.nextSibling ();
254 | }
255 |
256 | }
257 |
258 | static void
259 | create_requst_pad (GstElement *element, const QString &templateName,
260 | const QString &padName)
261 | {
262 | GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
263 |
264 | GstPadTemplate *templ = gst_element_class_get_pad_template (
265 | klass, templateName.toStdString ().c_str ());
266 |
267 | gst_element_request_pad (element, templ, padName.toStdString ().c_str (),
268 | NULL);
269 | }
270 |
271 | bool
272 | PipelineIE::Export (QSharedPointer pgraph,
273 | const QString &fileName)
274 | {
275 | QFile file (fileName);
276 |
277 | if (!file.open (QIODevice::WriteOnly)) {
278 | QMessageBox::warning (0, "Read only", "The file is in read only mode");
279 | return false;
280 | }
281 |
282 | std::vector info = pgraph->GetInfo ();
283 |
284 | QXmlStreamWriter xmlWriter;
285 | xmlWriter.setDevice (&file);
286 | xmlWriter.writeStartDocument ();
287 | xmlWriter.writeStartElement ("pipeline");
288 |
289 | for (std::size_t i = 0; i < info.size (); i++) {
290 | xmlWriter.writeStartElement ("element");
291 |
292 | xmlWriter.writeAttribute ("name", info[i].m_name.c_str ());
293 | xmlWriter.writeAttribute ("plugin-name", info[i].m_pluginName.c_str ());
294 |
295 | GstElement *element = gst_bin_get_by_name (GST_BIN (pgraph->m_pGraph),
296 | info[i].m_name.c_str ());
297 |
298 | for (std::size_t j = 0; j < info[i].m_pads.size (); j++) {
299 | xmlWriter.writeStartElement ("pad");
300 |
301 | xmlWriter.writeAttribute ("name", info[i].m_pads[j].m_name.c_str ());
302 |
303 | GstPad *pad = gst_element_get_static_pad (
304 | element, info[i].m_pads[j].m_name.c_str ());
305 |
306 | GstPadTemplate *templ = gst_pad_get_pad_template (pad);
307 | if (templ) {
308 | QString presence;
309 | switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
310 | case GST_PAD_ALWAYS:
311 | presence = "always";
312 | break;
313 |
314 | case GST_PAD_SOMETIMES:
315 | presence = "sometimes";
316 | break;
317 |
318 | case GST_PAD_REQUEST:
319 | presence = "request";
320 | break;
321 | };
322 |
323 | xmlWriter.writeAttribute ("presence", presence);
324 | xmlWriter.writeAttribute ("template-name",
325 | GST_PAD_TEMPLATE_NAME_TEMPLATE (templ));
326 | }
327 | else {
328 | LOG_INFO("Unable to find a template for %s", info[i].m_pads[j].m_name.c_str());
329 | xmlWriter.writeAttribute ("presence", "always");
330 | xmlWriter.writeAttribute ("template-name", "");
331 | }
332 | gst_object_unref (pad);
333 |
334 | if (info[i].m_connections[j].m_elementId != (size_t) -1
335 | && info[i].m_connections[j].m_padId != (size_t) -1) {
336 | std::size_t elementPos, padPos;
337 | for (elementPos = 0; elementPos < info.size (); elementPos++) {
338 | if (info[elementPos].m_id == info[i].m_connections[j].m_elementId) {
339 | for (padPos = 0; padPos < info[elementPos].m_pads.size (); padPos++)
340 | if (info[elementPos].m_pads[padPos].m_id
341 | == info[i].m_connections[j].m_padId)
342 | break;
343 |
344 | if (padPos < info[elementPos].m_pads.size ())
345 | break;
346 | }
347 | }
348 | if (elementPos < info.size ()
349 | && padPos < info[elementPos].m_pads.size ()) {
350 | xmlWriter.writeStartElement ("connected-to");
351 | xmlWriter.writeAttribute ("element-name",
352 | info[elementPos].m_name.c_str ());
353 | xmlWriter.writeAttribute (
354 | "pad-name", info[elementPos].m_pads[padPos].m_name.c_str ());
355 | xmlWriter.writeEndElement ();
356 | }
357 | }
358 |
359 | xmlWriter.writeEndElement ();
360 | }
361 |
362 | writeProperties (xmlWriter, element);
363 | gst_object_unref (element);
364 |
365 | xmlWriter.writeEndElement ();
366 | }
367 |
368 | xmlWriter.writeEndElement ();
369 | xmlWriter.writeEndDocument ();
370 |
371 | return true;
372 | }
373 |
374 | bool
375 | PipelineIE::Import (QSharedPointer pgraph,
376 | const QString &fileName)
377 | {
378 | GstElement *pipeline = pgraph->m_pGraph;
379 | QFile file (fileName);
380 | if (!file.open (QFile::ReadOnly | QFile::Text)) {
381 | QMessageBox::warning (
382 | 0, "Open failed",
383 | QString ("Cannot read file ") + fileName + ": " + file.errorString ());
384 |
385 | return false;
386 | }
387 |
388 | QString errorStr;
389 | int errorLine;
390 | int errorColumn;
391 |
392 | QDomDocument doc;
393 | if (!doc.setContent (&file, false, &errorStr, &errorLine, &errorColumn)) {
394 | QMessageBox::warning (
395 | 0, "Xml parsing failed",
396 | QString ("Parse error at line ") + QString::number (errorLine) + ", "
397 | "column " + QString::number (errorColumn) + ": " + errorStr);
398 | return false;
399 | }
400 |
401 | clearPipeline (pipeline);
402 |
403 | QDomElement root = doc.documentElement ();
404 |
405 | if (root.tagName () != "pipeline") {
406 | QMessageBox::warning (0, "Parsing failed", "Is invalid pipeline file");
407 | return false;
408 | }
409 |
410 | QDomNode child = root.firstChild ();
411 |
412 | std::vector connections;
413 | while (!child.isNull ()) {
414 | if (child.toElement ().tagName () == "element") {
415 | QDomElement elNode = child.toElement ();
416 |
417 | GstElement *pel = gst_element_factory_make (
418 | elNode.attribute ("plugin-name").toStdString ().c_str (),
419 | elNode.attribute ("name").toStdString ().c_str ());
420 |
421 | if (!pel) {
422 | QMessageBox::warning (
423 | 0,
424 | "Element creation failed",
425 | QString ("Could not create element of `")
426 | + elNode.attribute ("plugin-name") + "` with name `"
427 | + elNode.attribute ("name") + "`");
428 |
429 | child = child.nextSibling ();
430 | continue;
431 | }
432 |
433 | bool res = gst_bin_add (GST_BIN (pipeline), pel);
434 |
435 | if (!res) {
436 | QMessageBox::warning (
437 | 0,
438 | "Element insertion failed",
439 | QString ("Could not insert element `") + elNode.attribute ("name")
440 | + "` to pipeline");
441 |
442 | child = child.nextSibling ();
443 | continue;
444 | }
445 |
446 | gst_element_sync_state_with_parent (pel);
447 |
448 | QDomNode elementChild = elNode.firstChild ();
449 | while (!elementChild.isNull ()) {
450 | if (elementChild.toElement ().tagName () == "pad") {
451 | QDomNode padChild = elementChild.firstChild ();
452 | QDomElement elPad = elementChild.toElement ();
453 | // GstPadPresence presence = GST_PAD_ALWAYS;
454 |
455 | QString templaneName;
456 | if (elPad.attribute ("presence") == "request")
457 | create_requst_pad (pel, elPad.attribute ("template-name"),
458 | elPad.attribute ("name"));
459 |
460 | while (!padChild.isNull ()) {
461 | if (padChild.toElement ().tagName () == "connected-to") {
462 | bool isExists = false;
463 | QDomElement elCoonnectedTo = padChild.toElement ();
464 |
465 | for (std::size_t i = 0; i < connections.size (); i++) {
466 | if ((connections[i].element1
467 | == elNode.attribute ("name").toStdString ()
468 | && connections[i].element2
469 | == elCoonnectedTo.attribute ("element-name").toStdString ()
470 | && connections[i].pad1
471 | == elPad.attribute ("name").toStdString ()
472 | && connections[i].pad2
473 | == elCoonnectedTo.attribute ("pad-name").toStdString ())
474 | || (connections[i].element2
475 | == elNode.attribute ("name").toStdString ()
476 | && connections[i].element1
477 | == elCoonnectedTo.attribute ("element-name").toStdString ()
478 | && connections[i].pad2
479 | == elPad.attribute ("name").toStdString ()
480 | && connections[i].pad1
481 | == elCoonnectedTo.attribute ("pad-name").toStdString ())) {
482 | isExists = true;
483 | }
484 | }
485 |
486 | if (!isExists) {
487 | Connection newConnetion;
488 | newConnetion.element1 =
489 | elNode.attribute ("name").toStdString ();
490 | newConnetion.element2 = padChild.toElement ().attribute (
491 | "element-name").toStdString ();
492 | newConnetion.pad1 =
493 | elementChild.toElement ().attribute ("name").toStdString ();
494 | newConnetion.pad2 =
495 | padChild.toElement ().attribute ("pad-name").toStdString ();
496 |
497 | connections.push_back (newConnetion);
498 | }
499 | }
500 | padChild = padChild.nextSibling ();
501 | }
502 | }
503 | else if (elementChild.toElement ().tagName () == "properties") {
504 | loadProperties (elementChild.toElement (), pel);
505 | }
506 | elementChild = elementChild.nextSibling ();
507 | }
508 | }
509 | child = child.nextSibling ();
510 | }
511 |
512 | std::size_t maxStarts = 5;
513 | bool setReady = true;
514 | for (std::size_t k = 0; k < maxStarts; k++) {
515 | if (connections.empty ())
516 | break;
517 |
518 | if (k > 0)
519 | setReady = false;
520 |
521 | while (true) {
522 | std::size_t i = 0;
523 | for (; i < connections.size (); i++) {
524 | GstElement *el1 = gst_bin_get_by_name (
525 | GST_BIN (pipeline), connections[i].element1.c_str ());
526 | GstElement *el2 = gst_bin_get_by_name (
527 | GST_BIN (pipeline), connections[i].element2.c_str ());
528 |
529 | if (!el1 || !el2) {
530 | QMessageBox::warning (
531 | 0,
532 | "Internal error",
533 | QString ("Could not find one of elements `")
534 | + QString (connections[i].element1.c_str ()) + "`, `"
535 | + QString (connections[i].element2.c_str ()) + "`");
536 |
537 | gst_object_unref (el1);
538 | gst_object_unref (el2);
539 |
540 | return false;
541 | }
542 |
543 | GstPad *pad1 = gst_element_get_static_pad (
544 | el1, connections[i].pad1.c_str ());
545 | GstPad *pad2 = gst_element_get_static_pad (
546 | el2, connections[i].pad2.c_str ());
547 |
548 | if (pad1 && pad2) {
549 | if (GST_PAD_IS_SRC (pad1))
550 | gst_element_link_pads (el1, connections[i].pad1.c_str (), el2,
551 | connections[i].pad2.c_str ());
552 | else
553 | gst_element_link_pads (el2, connections[i].pad2.c_str (), el1,
554 | connections[i].pad1.c_str ());
555 |
556 | gst_object_unref (pad1);
557 | gst_object_unref (pad2);
558 | connections.erase (connections.begin () + i);
559 |
560 | gst_object_unref (el1);
561 | gst_object_unref (el2);
562 |
563 | break;
564 | }
565 |
566 | if (pad1)
567 | gst_object_unref (pad1);
568 |
569 | if (pad2)
570 | gst_object_unref (pad2);
571 |
572 | gst_object_unref (el1);
573 | gst_object_unref (el2);
574 | }
575 |
576 | if (i == connections.size ())
577 | break;
578 | }
579 |
580 | if (!connections.empty ()) {
581 | gst_element_set_state (pipeline, GST_STATE_PAUSED);
582 |
583 | GstState state;
584 | gst_element_get_state (pipeline, &state, NULL, GST_MSECOND * 2500);
585 | }
586 |
587 | }
588 |
589 | if (setReady)
590 | gst_element_set_state (pipeline, GST_STATE_READY);
591 |
592 | return true;
593 | }
594 |
595 | bool
596 | PipelineIE::Clear (QSharedPointer pgraph)
597 | {
598 | GstElement *pipeline = pgraph->m_pGraph;
599 | clearPipeline (pipeline);
600 | return true;
601 | }
602 |
--------------------------------------------------------------------------------
/src/PipelineIE.h:
--------------------------------------------------------------------------------
1 | #ifndef PIPELINE_IMPORT_EXPORT_H_
2 | #define PIPELINE_IMPORT_EXPORT_H_
3 |
4 | #include
5 | #include
6 |
7 | #include "GraphManager.h"
8 |
9 | namespace PipelineIE
10 | {
11 | bool Export(QSharedPointer pgraph, const QString &fileName);
12 | bool Import(QSharedPointer pgraph, const QString &fileName);
13 | bool Clear(QSharedPointer pgraph);
14 | };
15 |
16 | #endif
17 |
--------------------------------------------------------------------------------
/src/PluginsList.cpp:
--------------------------------------------------------------------------------
1 | #include "PluginsList.h"
2 | #include "MainWindow.h"
3 | #include "FavoritesList.h"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 |
18 | static gint
19 | plugins_sort_cb (gconstpointer a, gconstpointer b)
20 | {
21 | Plugin* p1 = (Plugin*) a;
22 | Plugin* p2 = (Plugin*) b;
23 | LOG_INFO("Sort p1: %s and p2: ", p1->getName ().toStdString ().c_str (),p2->getName ().toStdString ().c_str ());
24 | if (p1->getRank () > p2->getRank ())
25 | return 1;
26 | else if (p1->getRank () == p2->getRank ()) {
27 | return 0;
28 | }
29 | else {
30 | return -1;
31 | }
32 | }
33 |
34 | PluginsList::PluginsList ()
35 | :m_pluginsList(NULL)
36 | {
37 | init ();
38 | }
39 |
40 | PluginsList& PluginsList::instance()
41 | {
42 | static PluginsList instance;
43 | return instance;
44 | }
45 |
46 | PluginsList::~PluginsList ()
47 | {
48 | //g_list_free(m_pluginsList);
49 | }
50 |
51 | void
52 | PluginsList::init ()
53 | {
54 | std::size_t num = 0;
55 | GList *plugins;
56 | m_pluginsList = NULL;
57 | GstRegistry *registry;
58 | #if GST_VERSION_MAJOR >= 1
59 | registry = gst_registry_get();
60 | #else
61 | registry = gst_registry_get_default ();
62 | #endif
63 | plugins = gst_registry_get_plugin_list (registry);
64 | while (plugins) {
65 | GstPlugin *plugin;
66 | plugin = (GstPlugin *) (plugins->data);
67 | plugins = g_list_next (plugins);
68 | #if GST_VERSION_MAJOR >= 1
69 | registry = gst_registry_get();
70 | #else
71 | registry = gst_registry_get_default ();
72 | #endif
73 | GList *features = gst_registry_get_feature_list_by_plugin (
74 | registry, gst_plugin_get_name (plugin));
75 |
76 | while (features) {
77 | GstPluginFeature *feature;
78 | feature = GST_PLUGIN_FEATURE (features->data);
79 | if (GST_IS_ELEMENT_FACTORY (feature)) {
80 | GstElementFactory *factory;
81 | factory = GST_ELEMENT_FACTORY (feature);
82 | int rank = gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory));
83 | Plugin* p = new Plugin (GST_OBJECT_NAME (factory), rank);
84 | m_pluginsList = g_list_append (m_pluginsList, p);
85 | num++;
86 | }
87 |
88 | features = g_list_next (features);
89 | }
90 | }
91 | }
92 |
93 | GList*
94 | PluginsList::getSortedByRank ()
95 | {
96 | GList* sorted_list = g_list_sort (m_pluginsList, plugins_sort_cb);
97 | return sorted_list;
98 | }
99 |
100 | GList*
101 | PluginsList::getPluginListByCaps (GstPadDirection direction, GstCaps* caps)
102 | {
103 | GList * caps_plugins_list = NULL;
104 | GList *l, *p;
105 |
106 | for (l = m_pluginsList; l != NULL; l = l->next) {
107 | Plugin* plugin = (Plugin*) (l->data);
108 | GstElementFactory* factory = gst_element_factory_find (
109 | plugin->getName ().toStdString ().c_str ());
110 | if (factory) {
111 | const GList* pads = gst_element_factory_get_static_pad_templates (
112 | factory);
113 | for (p = (GList*) pads; p != NULL; p = p->next) {
114 | GstStaticPadTemplate* padTemplate = (GstStaticPadTemplate*) (p->data);
115 | if (padTemplate->direction == direction
116 | && gst_caps_can_intersect (caps, padTemplate->static_caps.caps))
117 | caps_plugins_list = g_list_append (caps_plugins_list, plugin);
118 | }
119 | }
120 | }
121 | return caps_plugins_list;
122 | }
123 |
124 |
125 | #define kBUTTON_FAVORITE_ADD "Add to favorites"
126 | #define kBUTTON_FAVORITE_REMOVE "Remove from favorites"
127 |
128 | PluginsListDialog::PluginsListDialog (QWidget *pwgt,
129 | Qt::WindowFlags f)
130 | : QDialog (pwgt, f),
131 | m_pGraph (NULL)
132 | {
133 | m_main = (MainWindow*)pwgt;
134 |
135 | m_pPlugins = new QListWidget;
136 | m_pPlugins->setSortingEnabled (true);
137 | m_plblInfo = new QLabel;
138 |
139 | m_plblInfo->setTextInteractionFlags (Qt::TextSelectableByMouse);
140 | m_plblInfo->setAlignment (Qt::AlignLeft | Qt::AlignTop);
141 | QScrollArea *pscroll = new QScrollArea;
142 | pscroll->setWidget (m_plblInfo);
143 | m_plblInfo->resize (pscroll->size ());
144 |
145 | QHBoxLayout *phblay = new QHBoxLayout;
146 |
147 | phblay->addWidget (m_pPlugins, 1);
148 | phblay->addWidget (pscroll, 2);
149 |
150 | InitPluginsList ();
151 |
152 | QHBoxLayout *phblayFind = new QHBoxLayout;
153 |
154 | QLineEdit *ple = new QLineEdit;
155 | phblayFind->addWidget (ple);
156 | phblayFind->addStretch (1);
157 | ple->setPlaceholderText ("Search...");
158 |
159 | m_favoriteListButton = new QPushButton(kBUTTON_FAVORITE_ADD);
160 | phblayFind->addWidget (m_favoriteListButton);
161 | //phblayFind->addStretch (1);
162 | QObject::connect (m_favoriteListButton, SIGNAL (clicked ()), this,
163 | SLOT (favoritesClicked ()));
164 |
165 | QVBoxLayout *pvblay = new QVBoxLayout;
166 | pvblay->addLayout (phblayFind);
167 | pvblay->addLayout (phblay);
168 |
169 | setLayout (pvblay);
170 |
171 | setWindowTitle ("Add plugin");
172 |
173 | QObject::connect(m_pPlugins, SIGNAL(currentItemChanged (QListWidgetItem *, QListWidgetItem *)),
174 | this, SLOT(showInfo(QListWidgetItem *, QListWidgetItem *)));
175 |
176 | QObject::connect(m_pPlugins, SIGNAL(itemDoubleClicked (QListWidgetItem *)),
177 | this, SLOT(insert(QListWidgetItem *)));
178 |
179 | QObject::connect(m_pPlugins,SIGNAL(customContextMenuRequested(const QPoint &)),
180 | this,SLOT(ProvideContextMenu(const QPoint &)));
181 |
182 | QObject::connect(ple, SIGNAL(textChanged(const QString &)), this, SLOT(filterPlugins(const QString &)));
183 |
184 | installEventFilter (this);
185 | }
186 |
187 | PluginsListDialog::~PluginsListDialog ()
188 | {
189 | }
190 |
191 | void
192 | PluginsListDialog::showInfo (QListWidgetItem *pitem, QListWidgetItem *previous)
193 | {
194 |
195 | Q_UNUSED(previous);
196 | LOG_INFO("Show Info: %s", pitem->text ().toStdString ().c_str ());
197 | m_plblInfo->clear ();
198 | QString descr;
199 | descr += "Plugin details
";
200 |
201 | if (m_main->getFavoritesList()->isFavorite( pitem->text ()) != -1)
202 | m_favoriteListButton->setText(kBUTTON_FAVORITE_REMOVE);
203 | else
204 | m_favoriteListButton->setText(kBUTTON_FAVORITE_ADD);
205 |
206 | GstElementFactory *factory = gst_element_factory_find (
207 | pitem->text ().toStdString ().c_str ());
208 | if (!factory) {
209 | LOG_INFO("warning: %s not found",pitem->text ().toStdString ().c_str ());
210 | return;
211 | }
212 |
213 | factory = GST_ELEMENT_FACTORY (
214 | gst_plugin_feature_load (GST_PLUGIN_FEATURE (factory)));
215 | if (!factory) {
216 | LOG_INFO("warning: %s not found",pitem->text ().toStdString ().c_str ());
217 | return;
218 | }
219 | #if GST_VERSION_MAJOR >= 1
220 | GstPlugin *plugin = gst_plugin_feature_get_plugin (GST_PLUGIN_FEATURE (factory));
221 | #else
222 | const gchar* plugin_name = GST_PLUGIN_FEATURE (factory)->plugin_name;
223 | if (!plugin_name) {
224 | return;
225 | }
226 | GstPlugin* plugin = gst_default_registry_find_plugin (plugin_name);
227 | #endif
228 | if (!plugin) {
229 | LOG_INFO("warning: %s not found",pitem->text ().toStdString ().c_str ());
230 | return;
231 | }
232 |
233 | #if GST_VERSION_MAJOR >= 1
234 | const gchar *release_date = gst_plugin_get_release_date_string (plugin);
235 | #else
236 | const gchar *release_date =
237 | (plugin->desc.release_datetime) ? plugin->desc.release_datetime : "";
238 | #endif
239 | const gchar *filename = gst_plugin_get_filename (plugin);
240 |
241 | descr += "Name: " + QString (gst_plugin_get_name (plugin)) + "
";
242 | descr += "Description: "
243 | + QString (gst_plugin_get_description (plugin)) + "
";
244 | descr += "Filename: "
245 | + QString ((filename != NULL) ? filename : "(null)") + "
";
246 | descr += "Version: " + QString (gst_plugin_get_version (plugin))
247 | + "
";
248 | descr += "License: " + QString (gst_plugin_get_license (plugin))
249 | + "
";
250 | descr += "Source module: " + QString (gst_plugin_get_source (plugin))
251 | + "
";
252 |
253 | if (release_date != NULL) {
254 | const gchar *tz = "(UTC)";
255 | gchar *str, *sep;
256 |
257 | str = g_strdup (release_date);
258 | sep = strstr (str, "T");
259 | if (sep != NULL) {
260 | *sep = ' ';
261 | sep = strstr (sep + 1, "Z");
262 | if (sep != NULL)
263 | *sep = ' ';
264 | }
265 | else {
266 | tz = "";
267 | }
268 | descr += "Source release date: " + QString (str) + " " + QString (tz)
269 | + "
";
270 | g_free (str);
271 | }
272 | descr += "Binary package: " + QString (gst_plugin_get_package (plugin))
273 | + "
";
274 | descr += "Origin URL: " + QString (gst_plugin_get_origin (plugin))
275 | + "
";
276 | descr += "Rank: "
277 | + QString::number (
278 | gst_plugin_feature_get_rank (GST_PLUGIN_FEATURE (factory)));
279 | m_plblInfo->setText (descr);
280 | }
281 |
282 | void
283 | PluginsListDialog::insert (QListWidgetItem *pitem)
284 | {
285 | if (!pitem) {
286 | LOG_INFO("Do not insert null item");
287 | return;
288 | }
289 | LOG_INFO("Insert: %s", pitem->text ().toStdString ().c_str ());
290 |
291 | if (!m_pGraph
292 | || !m_pGraph->AddPlugin (pitem->text ().toStdString ().c_str (), NULL)) {
293 | QMessageBox::warning (
294 | this, "Plugin addition problem",
295 | "Plugin `" + pitem->text () + "` insertion was FAILED");
296 | LOG_INFO("Plugin `%s insertion FAILED", pitem->text ().toStdString ().c_str ());
297 | return;
298 | }
299 | }
300 |
301 | bool
302 | PluginsListDialog::eventFilter (QObject *obj, QEvent *event)
303 | {
304 | if (event->type () == QEvent::KeyPress) {
305 | QKeyEvent *key = static_cast (event);
306 |
307 | if (((key->key () == Qt::Key_Enter)
308 | || (key->key () == Qt::Key_Return)) && m_pPlugins->currentItem ()) {
309 | insert (m_pPlugins->currentItem ());
310 | return true;
311 | }
312 | }
313 | return QDialog::eventFilter (obj, event);
314 | }
315 |
316 | void
317 | PluginsListDialog::filterPlugins (const QString &text)
318 | {
319 | for (int i = 0; i < m_pPlugins->count (); i++) {
320 | QListWidgetItem *pitem = m_pPlugins->item (i);
321 |
322 | if (pitem->text ().contains (text))
323 | pitem->setHidden (false);
324 | else
325 | pitem->setHidden (true);
326 | }
327 | }
328 |
329 | void
330 | PluginsListDialog::favoritesClicked ()
331 | {
332 | QListWidgetItem *pitem = m_pPlugins->currentItem();
333 | if(!pitem)
334 | return;
335 | if (m_main->getFavoritesList()->isFavorite(pitem->text ()) != -1) {
336 | emit signalRemPluginToFav (pitem->text ());
337 | }
338 | else {
339 | emit signalAddPluginToFav (pitem->text ());
340 | }
341 | }
342 |
343 | void
344 | PluginsListDialog::InitPluginsList ()
345 | {
346 | GList* plugins_list = PluginsList::instance().getList ();
347 | GList* l;
348 | std::size_t num = 0;
349 |
350 | for (l = plugins_list; l != NULL; l = l->next) {
351 | Plugin* plugin = (Plugin*) (l->data);
352 | m_pPlugins->addItem (plugin->getName ());
353 | num++;
354 | }
355 | }
356 |
357 | void PluginsListDialog::ProvideContextMenu(const QPoint &pos)
358 | {
359 | QPoint item = m_pPlugins->mapToGlobal(pos);
360 | QListWidgetItem* current_item = m_pPlugins->currentItem();
361 |
362 | QMenu submenu;
363 | if (m_main->getFavoritesList()->isFavorite(current_item->text ()) != -1) {
364 | emit signalRemPluginToFav (current_item->text ());
365 | }
366 | else {
367 | emit signalAddPluginToFav (current_item->text ());
368 | }
369 |
370 | if (m_main->getFavoritesList()->isFavorite(current_item->text ()) != -1)
371 | submenu.addAction("Add to favorites");
372 | else
373 | submenu.addAction("Remove from favorites");
374 |
375 | QAction* rightClickItem = submenu.exec(item);
376 | if (rightClickItem) {
377 | if(rightClickItem->text().contains("Add to favorites") ) {
378 | LOG_INFO("Add item: %s", current_item->text().toStdString ().c_str ());
379 | emit signalAddPluginToFav (current_item->text ());
380 | } else if(rightClickItem->text().contains("Remove from favorites") ) {
381 | LOG_INFO("Delete item: %s", current_item->text().toStdString ().c_str ());
382 | emit signalRemPluginToFav (current_item->text ());
383 | }
384 | }
385 | }
386 |
--------------------------------------------------------------------------------
/src/PluginsList.h:
--------------------------------------------------------------------------------
1 | #ifndef PLUGINS_LIST_H_
2 | #define PLUGINS_LIST_H_
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "GraphManager.h"
10 |
11 | class Plugin
12 | {
13 | public:
14 | Plugin(const QString& name, int rank):
15 | m_name(name),
16 | m_rank(rank)
17 | {
18 | }
19 | const QString getName() {return m_name;}
20 | int getRank() {return m_rank;}
21 |
22 | private:
23 | const QString m_name;
24 | int m_rank;
25 |
26 | };
27 |
28 | class PluginsList
29 | {
30 | public:
31 | PluginsList();
32 | ~PluginsList();
33 |
34 | static PluginsList& instance();
35 |
36 | GList* getList() {return m_pluginsList;}
37 | GList* getSortedByRank();
38 | GList* getPluginListByCaps(GstPadDirection direction, GstCaps* caps);
39 | GList* getPluginListFavorite();
40 |
41 | private:
42 | void init();
43 |
44 | GList* m_pluginsList; //list of plugins
45 | };
46 |
47 | class MainWindow;
48 |
49 | class PluginsListDialog: public QDialog
50 | {
51 | Q_OBJECT
52 | public:
53 | PluginsListDialog(QWidget *pwgt = NULL, Qt::WindowFlags f = Qt::Window);
54 | ~PluginsListDialog();
55 |
56 | void setGraph(GraphManager* graph) {m_pGraph = graph;}
57 |
58 | protected:
59 | bool eventFilter(QObject *obj, QEvent *ev);
60 |
61 | private:
62 | void InitPluginsList();
63 |
64 | public slots:
65 | void showInfo(QListWidgetItem *current, QListWidgetItem *previous);
66 | void insert(QListWidgetItem *);
67 |
68 | private slots:
69 | void filterPlugins(const QString &text);
70 | void favoritesClicked();
71 | void ProvideContextMenu(const QPoint &pos);
72 |
73 | signals:
74 | void signalAddPluginToFav (const QString &plugin_name);
75 | void signalRemPluginToFav (const QString &plugin_name);
76 |
77 | private:
78 | MainWindow * m_main;
79 | QLabel *m_plblInfo;
80 | QListWidget *m_pPlugins;
81 | GraphManager *m_pGraph;
82 | QPushButton*m_favoriteListButton;
83 | };
84 |
85 | #endif
86 |
--------------------------------------------------------------------------------
/src/SeekSlider.cpp:
--------------------------------------------------------------------------------
1 | #include "SeekSlider.h"
2 |
3 | void
4 | SeekSlider::mousePressEvent (QMouseEvent *event)
5 | {
6 | if (event->button () == Qt::LeftButton) {
7 | if (orientation () == Qt::Vertical)
8 | setValue (minimum ()
9 | + ((maximum () - minimum ()) * (height () - event->y ())) / height ());
10 | else
11 | setValue (minimum ()
12 | + ((maximum () - minimum ()) * event->x ()) / width ());
13 |
14 | event->accept ();
15 | }
16 |
17 | QSlider::mousePressEvent (event);
18 | }
19 | ;
20 |
--------------------------------------------------------------------------------
/src/SeekSlider.h:
--------------------------------------------------------------------------------
1 | #ifndef SEEK_SLIDER_H_
2 | #define SEEK_SLIDER_H_
3 |
4 | #include
5 | #include
6 |
7 | class SeekSlider: public QSlider
8 | {
9 | protected:
10 | void mousePressEvent(QMouseEvent *);
11 | };
12 |
13 | #endif
14 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "MainWindow.h"
3 |
4 | #include
5 |
6 | int
7 | main (int argc, char **argv)
8 | {
9 | Logger::instance().configure_logger ();
10 | gst_init (&argc, &argv);
11 |
12 | GstRegistry *registry;
13 | #if GST_VERSION_MAJOR >= 1
14 | registry = gst_registry_get();
15 | #else
16 | registry = gst_registry_get_default ();
17 | #endif
18 | gst_registry_scan_path (registry, "./plugins");
19 |
20 | QApplication app (argc, argv);
21 |
22 | MainWindow wgt;
23 | wgt.show ();
24 |
25 | return app.exec ();
26 | }
27 |
--------------------------------------------------------------------------------
/src/verinfo/verinfo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | version_file=$1
6 | out_file=$2
7 |
8 | major=`sed -n '1p' $version_file`
9 | minor=`sed -n '2p' $version_file`
10 |
11 | commit=`git rev-list --count HEAD 2>/dev/null || echo 0`
12 | if [ x"$commit" = 0 ]; then
13 | date=0
14 | else
15 | date=`date +'%d%m'%y`
16 | fi
17 |
18 | mkdir -p -- "${out_file%/*}"
19 | t=$(mktemp "$out_file".XXXXXXXX)
20 | trap 'rm -f -- "$out_file"' EXIT
21 |
22 | echo "#ifndef VERSION_INFO_H_" > $t
23 | echo "#define VERSION_INFO_H_" >> $t
24 | echo "" >> $t
25 | echo "#define VERSION_STR \"$major.$minor.$commit.$date\"" >> $t
26 | echo "" >> $t
27 | echo "#endif" >> $t
28 |
29 | if test -e "$out_file" && cmp -s "$out_file" "$s"; then
30 | rm -- "$t"
31 | else
32 | mv -f -- "$t" "$out_file"
33 | fi
34 | trap - EXIT
35 |
--------------------------------------------------------------------------------
/src/version.in:
--------------------------------------------------------------------------------
1 | 0
2 | 1
3 |
--------------------------------------------------------------------------------